[NFC] Pass position as an argument in WasmBinaryReader

Remove the `pos` member variable that keeps track of the current
position in the input buffer and instead thread the position through all
the calls to the parsing methods. In a future PR that paralellizes the
parsing of function bodies, this will enable the parsing methods to be
called in parallel without unsafely modifying shared state. Using a
parameter for every method rather than just those used while parsing
function bodies makes it impossible by construction to have data races
on the position.
diff --git a/src/wasm-binary.h b/src/wasm-binary.h
index 7c32e21..4bd6ff6 100644
--- a/src/wasm-binary.h
+++ b/src/wasm-binary.h
@@ -1419,7 +1419,6 @@
 
   // Internal state.
 
-  size_t pos = 0;
   Index startIndex = -1;
   size_t codeSectionLocation;
   std::unordered_set<uint8_t> seenSections;
@@ -1442,67 +1441,58 @@
     skipFunctionBodies = skipFunctionBodies_;
   }
   void read();
-  void readCustomSection(size_t payloadLen);
+  void readCustomSection(size_t& pos, size_t payloadLen);
 
-  bool more() { return pos < input.size(); }
+  bool more(size_t& pos) { return pos < input.size(); }
 
-  std::string_view getByteView(size_t size);
-  uint8_t getInt8();
-  uint16_t getInt16();
-  uint32_t getInt32();
-  uint64_t getInt64();
-  uint8_t getLaneIndex(size_t lanes);
+  std::string_view getByteView(size_t& pos, size_t size);
+  uint8_t getInt8(size_t& pos);
+  uint16_t getInt16(size_t& pos);
+  uint32_t getInt32(size_t& pos);
+  uint64_t getInt64(size_t& pos);
+  uint8_t getLaneIndex(size_t& pos, size_t lanes);
   // it is unsafe to return a float directly, due to ABI issues with the
   // signalling bit
-  Literal getFloat32Literal();
-  Literal getFloat64Literal();
-  Literal getVec128Literal();
-  uint32_t getU32LEB();
-  uint64_t getU64LEB();
-  int32_t getS32LEB();
-  int64_t getS64LEB();
-  uint64_t getUPtrLEB();
+  Literal getFloat32Literal(size_t& pos);
+  Literal getFloat64Literal(size_t& pos);
+  Literal getVec128Literal(size_t& pos);
+  uint32_t getU32LEB(size_t& pos);
+  uint64_t getU64LEB(size_t& pos);
+  int32_t getS32LEB(size_t& pos);
+  int64_t getS64LEB(size_t& pos);
 
-  bool getBasicType(int32_t code, Type& out);
-  bool getBasicHeapType(int64_t code, HeapType& out);
+  bool getBasicType(size_t& pos, int32_t code, Type& out);
+  bool getBasicHeapType(size_t& pos, int64_t code, HeapType& out);
   // Read a value and get a type for it.
-  Type getType();
+  Type getType(size_t& pos);
   // Get a type given the initial S32LEB has already been read, and is provided.
-  Type getType(int initial);
-  HeapType getHeapType();
-  HeapType getIndexedHeapType();
+  Type getType(size_t& pos, int initial);
+  HeapType getHeapType(size_t& pos);
+  HeapType getIndexedHeapType(size_t& pos);
 
-  Type getConcreteType();
-  Name getInlineString(bool requireValid = true);
-  void verifyInt8(int8_t x);
-  void verifyInt16(int16_t x);
-  void verifyInt32(int32_t x);
-  void verifyInt64(int64_t x);
-  void readHeader();
-  void readStart();
-  void readMemories();
-  void readTypes();
+  Type getConcreteType(size_t& pos);
+  Name getInlineString(size_t& pos, bool requireValid = true);
+  void readHeader(size_t& pos);
+  void readStart(size_t& pos);
+  void readMemories(size_t& pos);
+  void readTypes(size_t& pos);
 
   // gets a name in the combined import+defined space
-  Name getFunctionName(Index index);
-  Name getTableName(Index index);
-  Name getMemoryName(Index index);
-  Name getGlobalName(Index index);
-  Name getTagName(Index index);
-  Name getDataName(Index index);
-  Name getElemName(Index index);
+  Name getFunctionName(size_t& pos, Index index);
+  Name getTableName(size_t& pos, Index index);
+  Name getMemoryName(size_t& pos, Index index);
+  Name getGlobalName(size_t& pos, Index index);
+  Name getTagName(size_t& pos, Index index);
+  Name getDataName(size_t& pos, Index index);
+  Name getElemName(size_t& pos, Index index);
 
-  // gets a memory in the combined import+defined space
-  Memory* getMemory(Index index);
-  // gets a table in the combined import+defined space
-  Table* getTable(Index index);
-
-  void getResizableLimits(Address& initial,
+  void getResizableLimits(size_t& pos,
+                          Address& initial,
                           Address& max,
                           bool& shared,
                           Type& addressType,
                           Address defaultIfNoMax);
-  void readImports();
+  void readImports(size_t& pos);
 
   // The signatures of each function, including imported functions, given in the
   // import and function sections. Store HeapTypes instead of Signatures because
@@ -1514,13 +1504,11 @@
   Index numFuncImports = 0;
   Index numFuncBodies = 0;
 
-  void readFunctionSignatures();
-  HeapType getTypeByIndex(Index index);
-  HeapType getTypeByFunctionIndex(Index index);
-  Signature getSignatureByTypeIndex(Index index);
-  Signature getSignatureByFunctionIndex(Index index);
-
-  Name getNextLabel();
+  void readFunctionSignatures(size_t& pos);
+  HeapType getTypeByIndex(size_t& pos, Index index);
+  HeapType getTypeByFunctionIndex(size_t& pos, Index index);
+  Signature getSignatureByTypeIndex(size_t& pos, Index index);
+  Signature getSignatureByFunctionIndex(size_t& pos, Index index);
 
   // We read the names section first so we know in advance what names various
   // elements should have. Store the information for use when building
@@ -1541,50 +1529,47 @@
   // function to check
   Index endOfFunction = -1;
 
-  // Throws a parsing error if we are not in a function context
-  void requireFunctionContext(const char* error);
-
-  void readFunctions();
-  void readVars();
+  void readFunctions(size_t& pos);
+  void readVars(size_t& pos);
   void setLocalNames(Function& func, Index i);
 
-  Result<> readInst();
+  Result<> readInst(size_t& pos);
 
-  void readExports();
+  void readExports(size_t& pos);
 
   // The strings in the strings section (which are referred to by StringConst).
   std::vector<Name> strings;
-  void readStrings();
-  Name getIndexedString();
+  void readStrings(size_t& pos);
+  Name getIndexedString(size_t& pos);
 
-  Expression* readExpression();
-  void readGlobals();
+  Expression* readExpression(size_t& pos);
+  void readGlobals(size_t& pos);
 
   // validations that cannot be performed on the Module
-  void validateBinary();
+  void validateBinary(size_t& pos);
 
   size_t dataCount = 0;
   bool hasDataCount = false;
 
   void createDataSegments(Index count);
-  void readDataSegments();
-  void readDataSegmentCount();
+  void readDataSegments(size_t& pos);
+  void readDataSegmentCount(size_t& pos);
 
-  void readTableDeclarations();
-  void readElementSegments();
+  void readTableDeclarations(size_t& pos);
+  void readElementSegments(size_t& pos);
 
-  void readTags();
+  void readTags(size_t& pos);
 
   static Name escape(Name name);
   void findAndReadNames();
-  void readFeatures(size_t);
-  void readDylink(size_t);
-  void readDylink0(size_t);
+  void readFeatures(size_t& pos, size_t payloadLen);
+  void readDylink(size_t& pos, size_t payloadLen);
+  void readDylink0(size_t& pos, size_t payloadLen);
 
-  Index readMemoryAccess(Address& alignment, Address& offset);
-  std::tuple<Name, Address, Address> getMemarg();
+  Index readMemoryAccess(size_t& pos, Address& alignment, Address& offset);
+  std::tuple<Name, Address, Address> getMemarg(size_t& pos);
 
-  [[noreturn]] void throwError(std::string text) {
+  [[noreturn]] void throwError(size_t pos, std::string text) {
     throw ParseException(text, 0, pos);
   }
 
diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp
index 86b3ea8..89fe4fc 100644
--- a/src/wasm/wasm-binary.cpp
+++ b/src/wasm/wasm-binary.cpp
@@ -1745,19 +1745,19 @@
 }
 
 bool WasmBinaryReader::hasDWARFSections() {
-  assert(pos == 0);
-  getInt32(); // magic
-  getInt32(); // version
+  size_t pos = 0;
+  getInt32(pos); // magic
+  getInt32(pos); // version
   bool has = false;
-  while (more()) {
-    uint8_t sectionCode = getInt8();
-    uint32_t payloadLen = getU32LEB();
+  while (more(pos)) {
+    uint8_t sectionCode = getInt8(pos);
+    uint32_t payloadLen = getU32LEB(pos);
     if (uint64_t(pos) + uint64_t(payloadLen) > input.size()) {
-      throwError("Section extends beyond end of input");
+      throwError(pos, "Section extends beyond end of input");
     }
     auto oldPos = pos;
     if (sectionCode == BinaryConsts::Section::Custom) {
-      auto sectionName = getInlineString();
+      auto sectionName = getInlineString(pos);
       if (Debug::isDWARFSection(sectionName)) {
         has = true;
         break;
@@ -1765,7 +1765,6 @@
     }
     pos = oldPos + payloadLen;
   }
-  pos = 0;
   return has;
 }
 
@@ -1787,15 +1786,16 @@
     findAndReadNames();
   }
 
-  readHeader();
+  size_t pos = 0;
+  readHeader(pos);
   sourceMapReader.readHeader(wasm);
 
   // Read sections until the end
-  while (more()) {
-    uint8_t sectionCode = getInt8();
-    uint32_t payloadLen = getU32LEB();
+  while (more(pos)) {
+    uint8_t sectionCode = getInt8(pos);
+    uint32_t payloadLen = getU32LEB(pos);
     if (uint64_t(pos) + uint64_t(payloadLen) > input.size()) {
-      throwError("Section extends beyond end of input");
+      throwError(pos, "Section extends beyond end of input");
     }
 
     auto oldPos = pos;
@@ -1804,99 +1804,103 @@
     // appear more than once, and verify those that shouldn't do not.
     if (sectionCode != BinaryConsts::Section::Custom &&
         !seenSections.insert(sectionCode).second) {
-      throwError("section seen more than once: " + std::to_string(sectionCode));
+      throwError(pos,
+                 "section seen more than once: " + std::to_string(sectionCode));
     }
 
     switch (sectionCode) {
       case BinaryConsts::Section::Start:
-        readStart();
+        readStart(pos);
         break;
       case BinaryConsts::Section::Memory:
-        readMemories();
+        readMemories(pos);
         break;
       case BinaryConsts::Section::Type:
-        readTypes();
+        readTypes(pos);
         break;
       case BinaryConsts::Section::Import:
-        readImports();
+        readImports(pos);
         break;
       case BinaryConsts::Section::Function:
-        readFunctionSignatures();
+        readFunctionSignatures(pos);
         break;
       case BinaryConsts::Section::Code:
         if (DWARF) {
           codeSectionLocation = pos;
         }
-        readFunctions();
+        readFunctions(pos);
         break;
       case BinaryConsts::Section::Export:
-        readExports();
+        readExports(pos);
         break;
       case BinaryConsts::Section::Element:
-        readElementSegments();
+        readElementSegments(pos);
         break;
       case BinaryConsts::Section::Strings:
-        readStrings();
+        readStrings(pos);
         break;
       case BinaryConsts::Section::Global:
-        readGlobals();
+        readGlobals(pos);
         break;
       case BinaryConsts::Section::Data:
-        readDataSegments();
+        readDataSegments(pos);
         break;
       case BinaryConsts::Section::DataCount:
-        readDataSegmentCount();
+        readDataSegmentCount(pos);
         break;
       case BinaryConsts::Section::Table:
-        readTableDeclarations();
+        readTableDeclarations(pos);
         break;
       case BinaryConsts::Section::Tag:
-        readTags();
+        readTags(pos);
         break;
       case BinaryConsts::Section::Custom: {
-        readCustomSection(payloadLen);
+        readCustomSection(pos, payloadLen);
         if (pos > oldPos + payloadLen) {
-          throwError("bad user section size, started at " +
-                     std::to_string(oldPos) + " plus payload " +
-                     std::to_string(payloadLen) +
-                     " not being equal to new position " + std::to_string(pos));
+          throwError(
+            pos,
+            "bad user section size, started at " + std::to_string(oldPos) +
+              " plus payload " + std::to_string(payloadLen) +
+              " not being equal to new position " + std::to_string(pos));
         }
         pos = oldPos + payloadLen;
         break;
       }
       default:
-        throwError(std::string("unrecognized section ID: ") +
-                   std::to_string(sectionCode));
+        throwError(pos,
+                   std::string("unrecognized section ID: ") +
+                     std::to_string(sectionCode));
     }
 
     // make sure we advanced exactly past this section
     if (pos != oldPos + payloadLen) {
-      throwError("bad section size, started at " + std::to_string(oldPos) +
-                 " plus payload " + std::to_string(payloadLen) +
-                 " not being equal to new position " + std::to_string(pos));
+      throwError(pos,
+                 "bad section size, started at " + std::to_string(oldPos) +
+                   " plus payload " + std::to_string(payloadLen) +
+                   " not being equal to new position " + std::to_string(pos));
     }
   }
 
-  validateBinary();
+  validateBinary(pos);
 }
 
-void WasmBinaryReader::readCustomSection(size_t payloadLen) {
+void WasmBinaryReader::readCustomSection(size_t& pos, size_t payloadLen) {
   auto oldPos = pos;
-  Name sectionName = getInlineString();
+  Name sectionName = getInlineString(pos);
   size_t read = pos - oldPos;
   if (read > payloadLen) {
-    throwError("bad user section size");
+    throwError(pos, "bad user section size");
   }
   payloadLen -= read;
   if (sectionName.equals(BinaryConsts::CustomSections::Name)) {
     // We already read the name section before anything else.
     pos += payloadLen;
   } else if (sectionName.equals(BinaryConsts::CustomSections::TargetFeatures)) {
-    readFeatures(payloadLen);
+    readFeatures(pos, payloadLen);
   } else if (sectionName.equals(BinaryConsts::CustomSections::Dylink)) {
-    readDylink(payloadLen);
+    readDylink(pos, payloadLen);
   } else if (sectionName.equals(BinaryConsts::CustomSections::Dylink0)) {
-    readDylink0(payloadLen);
+    readDylink0(pos, payloadLen);
   } else {
     // an unfamiliar custom section
     if (sectionName.equals(BinaryConsts::CustomSections::Linking)) {
@@ -1907,98 +1911,98 @@
     wasm.customSections.resize(wasm.customSections.size() + 1);
     auto& section = wasm.customSections.back();
     section.name = sectionName.str;
-    auto data = getByteView(payloadLen);
+    auto data = getByteView(pos, payloadLen);
     section.data = {data.begin(), data.end()};
   }
 }
 
-std::string_view WasmBinaryReader::getByteView(size_t size) {
+std::string_view WasmBinaryReader::getByteView(size_t& pos, size_t size) {
   if (size > input.size() || pos > input.size() - size) {
-    throwError("unexpected end of input");
+    throwError(pos, "unexpected end of input");
   }
   pos += size;
   return {input.data() + (pos - size), size};
 }
 
-uint8_t WasmBinaryReader::getInt8() {
-  if (!more()) {
-    throwError("unexpected end of input");
+uint8_t WasmBinaryReader::getInt8(size_t& pos) {
+  if (!more(pos)) {
+    throwError(pos, "unexpected end of input");
   }
   return input[pos++];
 }
 
-uint16_t WasmBinaryReader::getInt16() {
-  auto ret = uint16_t(getInt8());
-  ret |= uint16_t(getInt8()) << 8;
+uint16_t WasmBinaryReader::getInt16(size_t& pos) {
+  auto ret = uint16_t(getInt8(pos));
+  ret |= uint16_t(getInt8(pos)) << 8;
   return ret;
 }
 
-uint32_t WasmBinaryReader::getInt32() {
-  auto ret = uint32_t(getInt16());
-  ret |= uint32_t(getInt16()) << 16;
+uint32_t WasmBinaryReader::getInt32(size_t& pos) {
+  auto ret = uint32_t(getInt16(pos));
+  ret |= uint32_t(getInt16(pos)) << 16;
   return ret;
 }
 
-uint64_t WasmBinaryReader::getInt64() {
-  auto ret = uint64_t(getInt32());
-  ret |= uint64_t(getInt32()) << 32;
+uint64_t WasmBinaryReader::getInt64(size_t& pos) {
+  auto ret = uint64_t(getInt32(pos));
+  ret |= uint64_t(getInt32(pos)) << 32;
   return ret;
 }
 
-uint8_t WasmBinaryReader::getLaneIndex(size_t lanes) {
-  auto ret = getInt8();
+uint8_t WasmBinaryReader::getLaneIndex(size_t& pos, size_t lanes) {
+  auto ret = getInt8(pos);
   if (ret >= lanes) {
-    throwError("Illegal lane index");
+    throwError(pos, "Illegal lane index");
   }
   return ret;
 }
 
-Literal WasmBinaryReader::getFloat32Literal() {
-  auto ret = Literal(getInt32());
+Literal WasmBinaryReader::getFloat32Literal(size_t& pos) {
+  auto ret = Literal(getInt32(pos));
   ret = ret.castToF32();
   return ret;
 }
 
-Literal WasmBinaryReader::getFloat64Literal() {
-  auto ret = Literal(getInt64());
+Literal WasmBinaryReader::getFloat64Literal(size_t& pos) {
+  auto ret = Literal(getInt64(pos));
   ret = ret.castToF64();
   return ret;
 }
 
-Literal WasmBinaryReader::getVec128Literal() {
+Literal WasmBinaryReader::getVec128Literal(size_t& pos) {
   std::array<uint8_t, 16> bytes;
   for (auto i = 0; i < 16; ++i) {
-    bytes[i] = getInt8();
+    bytes[i] = getInt8(pos);
   }
   auto ret = Literal(bytes.data());
   return ret;
 }
 
-uint32_t WasmBinaryReader::getU32LEB() {
+uint32_t WasmBinaryReader::getU32LEB(size_t& pos) {
   U32LEB ret;
-  ret.read([&]() { return getInt8(); });
+  ret.read([&]() { return getInt8(pos); });
   return ret.value;
 }
 
-uint64_t WasmBinaryReader::getU64LEB() {
+uint64_t WasmBinaryReader::getU64LEB(size_t& pos) {
   U64LEB ret;
-  ret.read([&]() { return getInt8(); });
+  ret.read([&]() { return getInt8(pos); });
   return ret.value;
 }
 
-int32_t WasmBinaryReader::getS32LEB() {
+int32_t WasmBinaryReader::getS32LEB(size_t& pos) {
   S32LEB ret;
-  ret.read([&]() { return (int8_t)getInt8(); });
+  ret.read([&]() { return (int8_t)getInt8(pos); });
   return ret.value;
 }
 
-int64_t WasmBinaryReader::getS64LEB() {
+int64_t WasmBinaryReader::getS64LEB(size_t& pos) {
   S64LEB ret;
-  ret.read([&]() { return (int8_t)getInt8(); });
+  ret.read([&]() { return (int8_t)getInt8(pos); });
   return ret.value;
 }
 
-bool WasmBinaryReader::getBasicType(int32_t code, Type& out) {
+bool WasmBinaryReader::getBasicType(size_t& pos, int32_t code, Type& out) {
   switch (code) {
     case BinaryConsts::EncodedType::i32:
       out = Type::i32;
@@ -2065,7 +2069,9 @@
   }
 }
 
-bool WasmBinaryReader::getBasicHeapType(int64_t code, HeapType& out) {
+bool WasmBinaryReader::getBasicHeapType(size_t& pos,
+                                        int64_t code,
+                                        HeapType& out) {
   switch (code) {
     case BinaryConsts::EncodedHeapType::func:
       out = HeapType::func;
@@ -2117,18 +2123,18 @@
   }
 }
 
-Type WasmBinaryReader::getType(int initial) {
+Type WasmBinaryReader::getType(size_t& pos, int initial) {
   // Single value types are negative; signature indices are non-negative
   if (initial >= 0) {
     // TODO: Handle block input types properly.
-    auto sig = getSignatureByTypeIndex(initial);
+    auto sig = getSignatureByTypeIndex(pos, initial);
     if (sig.params != Type::none) {
-      throwError("control flow inputs are not supported yet");
+      throwError(pos, "control flow inputs are not supported yet");
     }
     return sig.results;
   }
   Type type;
-  if (getBasicType(initial, type)) {
+  if (getBasicType(pos, initial, type)) {
     return type;
   }
   switch (initial) {
@@ -2136,109 +2142,87 @@
     case BinaryConsts::EncodedType::Empty:
       return Type::none;
     case BinaryConsts::EncodedType::nullable:
-      return Type(getHeapType(), Nullable);
+      return Type(getHeapType(pos), Nullable);
     case BinaryConsts::EncodedType::nonnullable:
-      return Type(getHeapType(), NonNullable);
+      return Type(getHeapType(pos), NonNullable);
     default:
-      throwError("invalid wasm type: " + std::to_string(initial));
+      throwError(pos, "invalid wasm type: " + std::to_string(initial));
   }
   WASM_UNREACHABLE("unexpected type");
 }
 
-Type WasmBinaryReader::getType() { return getType(getS32LEB()); }
+Type WasmBinaryReader::getType(size_t& pos) {
+  return getType(pos, getS32LEB(pos));
+}
 
-HeapType WasmBinaryReader::getHeapType() {
-  auto type = getS64LEB(); // TODO: Actually s33
+HeapType WasmBinaryReader::getHeapType(size_t& pos) {
+  auto type = getS64LEB(pos); // TODO: Actually s33
   // Single heap types are negative; heap type indices are non-negative
   if (type >= 0) {
     if (size_t(type) >= types.size()) {
-      throwError("invalid signature index: " + std::to_string(type));
+      throwError(pos, "invalid signature index: " + std::to_string(type));
     }
     return types[type];
   }
   auto share = Unshared;
   if (type == BinaryConsts::EncodedType::Shared) {
     share = Shared;
-    type = getS64LEB(); // TODO: Actually s33
+    type = getS64LEB(pos); // TODO: Actually s33
   }
   HeapType ht;
-  if (getBasicHeapType(type, ht)) {
+  if (getBasicHeapType(pos, type, ht)) {
     return ht.getBasic(share);
   } else {
-    throwError("invalid wasm heap type: " + std::to_string(type));
+    throwError(pos, "invalid wasm heap type: " + std::to_string(type));
   }
   WASM_UNREACHABLE("unexpected type");
 }
 
-HeapType WasmBinaryReader::getIndexedHeapType() {
-  auto index = getU32LEB();
+HeapType WasmBinaryReader::getIndexedHeapType(size_t& pos) {
+  auto index = getU32LEB(pos);
   if (index >= types.size()) {
-    throwError("invalid heap type index: " + std::to_string(index));
+    throwError(pos, "invalid heap type index: " + std::to_string(index));
   }
   return types[index];
 }
 
-Type WasmBinaryReader::getConcreteType() {
-  auto type = getType();
+Type WasmBinaryReader::getConcreteType(size_t& pos) {
+  auto type = getType(pos);
   if (!type.isConcrete()) {
-    throwError("non-concrete type when one expected");
+    throwError(pos, "non-concrete type when one expected");
   }
   return type;
 }
 
-Name WasmBinaryReader::getInlineString(bool requireValid) {
-  auto len = getU32LEB();
-  auto data = getByteView(len);
+Name WasmBinaryReader::getInlineString(size_t& pos, bool requireValid) {
+  auto len = getU32LEB(pos);
+  auto data = getByteView(pos, len);
   if (requireValid && !String::isUTF8(data)) {
-    throwError("invalid UTF-8 string");
+    throwError(pos, "invalid UTF-8 string");
   }
   return Name(data);
 }
 
-void WasmBinaryReader::verifyInt8(int8_t x) {
-  int8_t y = getInt8();
-  if (x != y) {
-    throwError("surprising value");
+void WasmBinaryReader::readHeader(size_t& pos) {
+  auto magic = getInt32(pos);
+  if (magic != BinaryConsts::Magic) {
+    throwError(pos, "suprising value");
   }
-}
-
-void WasmBinaryReader::verifyInt16(int16_t x) {
-  int16_t y = getInt16();
-  if (x != y) {
-    throwError("surprising value");
-  }
-}
-
-void WasmBinaryReader::verifyInt32(int32_t x) {
-  int32_t y = getInt32();
-  if (x != y) {
-    throwError("surprising value");
-  }
-}
-
-void WasmBinaryReader::verifyInt64(int64_t x) {
-  int64_t y = getInt64();
-  if (x != y) {
-    throwError("surprising value");
-  }
-}
-
-void WasmBinaryReader::readHeader() {
-  verifyInt32(BinaryConsts::Magic);
-  auto version = getInt32();
+  auto version = getInt32(pos);
   if (version != BinaryConsts::Version) {
     if (version == 0x1000d) {
-      throwError("this looks like a wasm component, which Binaryen does not "
+      throwError(pos,
+                 "this looks like a wasm component, which Binaryen does not "
                  "support yet (see "
                  "https://github.com/WebAssembly/binaryen/issues/6728)");
     }
-    throwError("invalid version");
+    throwError(pos, "invalid version");
   }
 }
 
-void WasmBinaryReader::readStart() {
-  startIndex = getU32LEB();
-  wasm.start = getFunctionName(startIndex);
+void WasmBinaryReader::readStart(size_t& pos) {
+  startIndex = getU32LEB(pos);
+  wasm.start = getFunctionName(pos, startIndex);
 }
 
 static Name makeName(std::string prefix, size_t counter) {
@@ -2261,8 +2245,8 @@
   }
 }
 
-void WasmBinaryReader::readMemories() {
-  auto num = getU32LEB();
+void WasmBinaryReader::readMemories(size_t& pos) {
+  auto num = getU32LEB(pos);
   auto numImports = wasm.memories.size();
   std::unordered_set<Name> usedNames;
   for (auto& [index, name] : memoryNames) {
@@ -2277,7 +2261,8 @@
       getOrMakeName(memoryNames, numImports + i, makeName("", i), usedNames);
     auto memory = Builder::makeMemory(name);
     memory->hasExplicitName = isExplicit;
-    getResizableLimits(memory->initial,
+    getResizableLimits(pos,
+                       memory->initial,
                        memory->max,
                        memory->shared,
                        memory->addressType,
@@ -2286,28 +2271,28 @@
   }
 }
 
-void WasmBinaryReader::readTypes() {
-  TypeBuilder builder(getU32LEB());
+void WasmBinaryReader::readTypes(size_t& pos) {
+  TypeBuilder builder(getU32LEB(pos));
 
   auto readHeapType = [&]() -> HeapType {
-    int64_t htCode = getS64LEB(); // TODO: Actually s33
+    int64_t htCode = getS64LEB(pos); // TODO: Actually s33
     auto share = Unshared;
     if (htCode == BinaryConsts::EncodedType::Shared) {
       share = Shared;
-      htCode = getS64LEB(); // TODO: Actually s33
+      htCode = getS64LEB(pos); // TODO: Actually s33
     }
     HeapType ht;
-    if (getBasicHeapType(htCode, ht)) {
+    if (getBasicHeapType(pos, htCode, ht)) {
       return ht.getBasic(share);
     }
     if (size_t(htCode) >= builder.size()) {
-      throwError("invalid type index: " + std::to_string(htCode));
+      throwError(pos, "invalid type index: " + std::to_string(htCode));
     }
     return builder.getTempHeapType(size_t(htCode));
   };
   auto makeType = [&](int32_t typeCode) {
     Type type;
-    if (getBasicType(typeCode, type)) {
+    if (getBasicType(pos, typeCode, type)) {
       return type;
     }
 
@@ -2326,20 +2311,20 @@
         return builder.getTempRefType(ht, nullability);
       }
       default:
-        throwError("unexpected type index: " + std::to_string(typeCode));
+        throwError(pos, "unexpected type index: " + std::to_string(typeCode));
     }
     WASM_UNREACHABLE("unexpected type");
   };
-  auto readType = [&]() { return makeType(getS32LEB()); };
+  auto readType = [&]() { return makeType(getS32LEB(pos)); };
 
   auto readSignatureDef = [&]() {
     std::vector<Type> params;
     std::vector<Type> results;
-    size_t numParams = getU32LEB();
+    size_t numParams = getU32LEB(pos);
     for (size_t j = 0; j < numParams; j++) {
       params.push_back(readType());
     }
-    auto numResults = getU32LEB();
+    auto numResults = getU32LEB(pos);
     for (size_t j = 0; j < numResults; j++) {
       results.push_back(readType());
     }
@@ -2356,7 +2341,7 @@
   };
 
   auto readMutability = [&]() {
-    switch (getU32LEB()) {
+    switch (getU32LEB(pos)) {
       case 0:
         return Immutable;
       case 1:
@@ -2369,7 +2354,7 @@
   auto readFieldDef = [&]() {
     // The value may be a general wasm type, or one of the types only possible
     // in a field.
-    auto typeCode = getS32LEB();
+    auto typeCode = getS32LEB(pos);
     if (typeCode == BinaryConsts::EncodedType::i8) {
       auto mutable_ = readMutability();
       return Field(Field::i8, mutable_);
@@ -2386,7 +2371,7 @@
 
   auto readStructDef = [&]() {
     FieldList fields;
-    size_t numFields = getU32LEB();
+    size_t numFields = getU32LEB(pos);
     for (size_t j = 0; j < numFields; j++) {
       fields.push_back(readFieldDef());
     }
@@ -2394,18 +2379,18 @@
   };
 
   for (size_t i = 0; i < builder.size(); i++) {
-    auto form = getInt8();
+    auto form = getInt8(pos);
     if (form == BinaryConsts::EncodedType::Rec) {
-      uint32_t groupSize = getU32LEB();
+      uint32_t groupSize = getU32LEB(pos);
       if (groupSize == 0u) {
         // TODO: Support groups of size zero by shrinking the builder.
-        throwError("Recursion groups of size zero not supported");
+        throwError(pos, "Recursion groups of size zero not supported");
       }
       // The group counts as one element in the type section, so we have to
       // allocate space for the extra types.
       builder.grow(groupSize - 1);
       builder.createRecGroup(i, groupSize);
-      form = getInt8();
+      form = getInt8(pos);
     }
     std::optional<uint32_t> superIndex;
     if (form == BinaryConsts::EncodedType::Sub ||
@@ -2413,19 +2398,20 @@
       if (form == BinaryConsts::EncodedType::Sub) {
         builder[i].setOpen();
       }
-      uint32_t supers = getU32LEB();
+      uint32_t supers = getU32LEB(pos);
       if (supers > 0) {
         if (supers != 1) {
-          throwError("Invalid type definition with " + std::to_string(supers) +
-                     " supertypes");
+          throwError(pos,
+                     "Invalid type definition with " + std::to_string(supers) +
+                       " supertypes");
         }
-        superIndex = getU32LEB();
+        superIndex = getU32LEB(pos);
       }
-      form = getInt8();
+      form = getInt8(pos);
     }
     if (form == BinaryConsts::SharedDef) {
       builder[i].setShared();
-      form = getInt8();
+      form = getInt8(pos);
     }
     if (form == BinaryConsts::EncodedType::Func) {
       builder[i] = readSignatureDef();
@@ -2436,12 +2422,12 @@
     } else if (form == BinaryConsts::EncodedType::Array) {
       builder[i] = Array(readFieldDef());
     } else {
-      throwError("Bad type form " + std::to_string(form));
+      throwError(pos, "Bad type form " + std::to_string(form));
     }
     if (superIndex) {
       if (*superIndex > builder.size()) {
-        throwError("Out of bounds supertype index " +
-                   std::to_string(*superIndex));
+        throwError(
+          pos, "Out of bounds supertype index " + std::to_string(*superIndex));
       }
       builder[i].subTypeOf(builder[*superIndex]);
     }
@@ -2492,100 +2478,87 @@
   }
 }
 
-Name WasmBinaryReader::getFunctionName(Index index) {
+Name WasmBinaryReader::getFunctionName(size_t& pos, Index index) {
   if (index >= wasm.functions.size()) {
-    throwError("invalid function index");
+    throwError(pos, "invalid function index");
   }
   return wasm.functions[index]->name;
 }
 
-Name WasmBinaryReader::getTableName(Index index) {
+Name WasmBinaryReader::getTableName(size_t& pos, Index index) {
   if (index >= wasm.tables.size()) {
-    throwError("invalid table index");
+    throwError(pos, "invalid table index");
   }
   return wasm.tables[index]->name;
 }
 
-Name WasmBinaryReader::getMemoryName(Index index) {
+Name WasmBinaryReader::getMemoryName(size_t& pos, Index index) {
   if (index >= wasm.memories.size()) {
-    throwError("invalid memory index");
+    throwError(pos, "invalid memory index");
   }
   return wasm.memories[index]->name;
 }
 
-Name WasmBinaryReader::getGlobalName(Index index) {
+Name WasmBinaryReader::getGlobalName(size_t& pos, Index index) {
   if (index >= wasm.globals.size()) {
-    throwError("invalid global index");
+    throwError(pos, "invalid global index");
   }
   return wasm.globals[index]->name;
 }
 
-Table* WasmBinaryReader::getTable(Index index) {
-  if (index < wasm.tables.size()) {
-    return wasm.tables[index].get();
-  }
-  throwError("Table index out of range.");
-}
-
-Name WasmBinaryReader::getTagName(Index index) {
+Name WasmBinaryReader::getTagName(size_t& pos, Index index) {
   if (index >= wasm.tags.size()) {
-    throwError("invalid tag index");
+    throwError(pos, "invalid tag index");
   }
   return wasm.tags[index]->name;
 }
 
-Name WasmBinaryReader::getDataName(Index index) {
+Name WasmBinaryReader::getDataName(size_t& pos, Index index) {
   if (index >= wasm.dataSegments.size()) {
-    throwError("invalid data segment index");
+    throwError(pos, "invalid data segment index");
   }
   return wasm.dataSegments[index]->name;
 }
 
-Name WasmBinaryReader::getElemName(Index index) {
+Name WasmBinaryReader::getElemName(size_t& pos, Index index) {
   if (index >= wasm.elementSegments.size()) {
-    throwError("invalid element segment index");
+    throwError(pos, "invalid element segment index");
   }
   return wasm.elementSegments[index]->name;
 }
 
-Memory* WasmBinaryReader::getMemory(Index index) {
-  if (index < wasm.memories.size()) {
-    return wasm.memories[index].get();
-  }
-  throwError("Memory index out of range.");
-}
-
-void WasmBinaryReader::getResizableLimits(Address& initial,
+void WasmBinaryReader::getResizableLimits(size_t& pos,
+                                          Address& initial,
                                           Address& max,
                                           bool& shared,
                                           Type& addressType,
                                           Address defaultIfNoMax) {
-  auto flags = getU32LEB();
+  auto flags = getU32LEB(pos);
   bool hasMax = (flags & BinaryConsts::HasMaximum) != 0;
   bool isShared = (flags & BinaryConsts::IsShared) != 0;
   bool is64 = (flags & BinaryConsts::Is64) != 0;
-  initial = is64 ? getU64LEB() : getU32LEB();
+  initial = is64 ? getU64LEB(pos) : getU32LEB(pos);
   if (isShared && !hasMax) {
-    throwError("shared memory must have max size");
+    throwError(pos, "shared memory must have max size");
   }
   shared = isShared;
   addressType = is64 ? Type::i64 : Type::i32;
   if (hasMax) {
-    max = is64 ? getU64LEB() : getU32LEB();
+    max = is64 ? getU64LEB(pos) : getU32LEB(pos);
   } else {
     max = defaultIfNoMax;
   }
 }
 
-void WasmBinaryReader::readImports() {
-  size_t num = getU32LEB();
+void WasmBinaryReader::readImports(size_t& pos) {
+  size_t num = getU32LEB(pos);
   Builder builder(wasm);
   std::unordered_set<Name> usedFunctionNames, usedTableNames, usedMemoryNames,
     usedGlobalNames, usedTagNames;
   for (size_t i = 0; i < num; i++) {
-    auto module = getInlineString();
-    auto base = getInlineString();
-    auto kind = (ExternalKind)getU32LEB();
+    auto module = getInlineString(pos);
+    auto base = getInlineString(pos);
+    auto kind = (ExternalKind)getU32LEB(pos);
     // We set a unique prefix for the name based on the kind. This ensures no
     // collisions between them, which can't occur here (due to the index i) but
     // could occur later due to the names section.
@@ -2596,13 +2569,15 @@
                         wasm.functions.size(),
                         makeName("fimport$", wasm.functions.size()),
                         usedFunctionNames);
-        auto index = getU32LEB();
-        functionTypes.push_back(getTypeByIndex(index));
-        auto type = getTypeByIndex(index);
+        auto index = getU32LEB(pos);
+        functionTypes.push_back(getTypeByIndex(pos, index));
+        auto type = getTypeByIndex(pos, index);
         if (!type.isSignature()) {
-          throwError(std::string("Imported function ") + module.toString() +
-                     '.' + base.toString() +
-                     "'s type must be a signature. Given: " + type.toString());
+          throwError(
+            pos,
+            std::string("Imported function ") + module.toString() + '.' +
+              base.toString() +
+              "'s type must be a signature. Given: " + type.toString());
         }
         auto curr = builder.makeFunction(name, type, {});
         curr->hasExplicitName = isExplicit;
@@ -2622,16 +2597,17 @@
         table->hasExplicitName = isExplicit;
         table->module = module;
         table->base = base;
-        table->type = getType();
+        table->type = getType(pos);
 
         bool is_shared;
-        getResizableLimits(table->initial,
+        getResizableLimits(pos,
+                           table->initial,
                            table->max,
                            is_shared,
                            table->addressType,
                            Table::kUnlimitedSize);
         if (is_shared) {
-          throwError("Tables may not be shared");
+          throwError(pos, "Tables may not be shared");
         }
         wasm.addTable(std::move(table));
         break;
@@ -2646,7 +2622,8 @@
         memory->hasExplicitName = isExplicit;
         memory->module = module;
         memory->base = base;
-        getResizableLimits(memory->initial,
+        getResizableLimits(pos,
+                           memory->initial,
                            memory->max,
                            memory->shared,
                            memory->addressType,
@@ -2660,10 +2637,10 @@
                         wasm.globals.size(),
                         makeName("gimport$", wasm.globals.size()),
                         usedGlobalNames);
-        auto type = getConcreteType();
-        auto mutable_ = getU32LEB();
+        auto type = getConcreteType(pos);
+        auto mutable_ = getU32LEB(pos);
         if (mutable_ & ~1) {
-          throwError("Global mutability must be 0 or 1");
+          throwError(pos, "Global mutability must be 0 or 1");
         }
         auto curr =
           builder.makeGlobal(name,
@@ -2682,9 +2659,9 @@
                         wasm.tags.size(),
                         makeName("eimport$", wasm.tags.size()),
                         usedTagNames);
-        getInt8(); // Reserved 'attribute' field
-        auto index = getU32LEB();
-        auto curr = builder.makeTag(name, getSignatureByTypeIndex(index));
+        getInt8(pos); // Reserved 'attribute' field
+        auto index = getU32LEB(pos);
+        auto curr = builder.makeTag(name, getSignatureByTypeIndex(pos, index));
         curr->hasExplicitName = isExplicit;
         curr->module = module;
         curr->base = base;
@@ -2692,7 +2669,7 @@
         break;
       }
       default: {
-        throwError("bad import kind");
+        throwError(pos, "bad import kind");
       }
     }
   }
@@ -2713,8 +2690,8 @@
   }
 }
 
-void WasmBinaryReader::readFunctionSignatures() {
-  size_t num = getU32LEB();
+void WasmBinaryReader::readFunctionSignatures(size_t& pos) {
+  size_t num = getU32LEB(pos);
   auto numImports = wasm.functions.size();
   std::unordered_set<Name> usedNames;
   for (auto& [index, name] : functionNames) {
@@ -2736,61 +2713,63 @@
   for (size_t i = 0; i < num; i++) {
     auto [name, isExplicit] =
       getOrMakeName(functionNames, numImports + i, makeName("", i), usedNames);
-    auto index = getU32LEB();
-    HeapType type = getTypeByIndex(index);
+    auto index = getU32LEB(pos);
+    HeapType type = getTypeByIndex(pos, index);
     functionTypes.push_back(type);
     // Check that the type is a signature.
-    getSignatureByTypeIndex(index);
+    getSignatureByTypeIndex(pos, index);
     auto func = Builder(wasm).makeFunction(name, type, {}, nullptr);
     func->hasExplicitName = isExplicit;
     wasm.addFunction(std::move(func));
   }
 }
 
-HeapType WasmBinaryReader::getTypeByIndex(Index index) {
+HeapType WasmBinaryReader::getTypeByIndex(size_t& pos, Index index) {
   if (index >= types.size()) {
-    throwError("invalid type index " + std::to_string(index) + " / " +
-               std::to_string(types.size()));
+    throwError(pos,
+               "invalid type index " + std::to_string(index) + " / " +
+                 std::to_string(types.size()));
   }
   return types[index];
 }
 
-HeapType WasmBinaryReader::getTypeByFunctionIndex(Index index) {
+HeapType WasmBinaryReader::getTypeByFunctionIndex(size_t& pos, Index index) {
   if (index >= functionTypes.size()) {
-    throwError("invalid function index");
+    throwError(pos, "invalid function index");
   }
   return functionTypes[index];
 }
 
-Signature WasmBinaryReader::getSignatureByTypeIndex(Index index) {
-  auto heapType = getTypeByIndex(index);
+Signature WasmBinaryReader::getSignatureByTypeIndex(size_t& pos, Index index) {
+  auto heapType = getTypeByIndex(pos, index);
   if (!heapType.isSignature()) {
-    throwError("invalid signature type " + heapType.toString());
+    throwError(pos, "invalid signature type " + heapType.toString());
   }
   return heapType.getSignature();
 }
 
-Signature WasmBinaryReader::getSignatureByFunctionIndex(Index index) {
-  auto heapType = getTypeByFunctionIndex(index);
+Signature WasmBinaryReader::getSignatureByFunctionIndex(size_t& pos,
+                                                        Index index) {
+  auto heapType = getTypeByFunctionIndex(pos, index);
   if (!heapType.isSignature()) {
-    throwError("invalid signature type " + heapType.toString());
+    throwError(pos, "invalid signature type " + heapType.toString());
   }
   return heapType.getSignature();
 }
 
-void WasmBinaryReader::readFunctions() {
-  numFuncBodies = getU32LEB();
+void WasmBinaryReader::readFunctions(size_t& pos) {
+  numFuncBodies = getU32LEB(pos);
   if (numFuncBodies + numFuncImports != wasm.functions.size()) {
-    throwError("invalid function section size, must equal types");
+    throwError(pos, "invalid function section size, must equal types");
   }
   if (DWARF) {
     builder.setBinaryLocation(&pos, codeSectionLocation);
   }
   for (size_t i = 0; i < numFuncBodies; i++) {
     auto sizePos = pos;
-    size_t size = getU32LEB();
+    size_t size = getU32LEB(pos);
     if (size == 0) {
-      throwError("empty function size");
+      throwError(pos, "empty function size");
     }
     Index endOfFunction = pos + size;
 
@@ -2806,7 +2785,7 @@
 
     func->prologLocation = sourceMapReader.readDebugLocationAt(pos);
 
-    readVars();
+    readVars(pos);
     setLocalNames(*func, numFuncImports + i);
     {
       // Process the function body. Even if we are skipping function bodies we
@@ -2827,19 +2806,19 @@
       } else {
         auto start = builder.visitFunctionStart(func.get());
         if (auto* err = start.getErr()) {
-          throwError(err->msg);
+          throwError(pos, err->msg);
         }
         while (pos < endOfFunction) {
-          auto inst = readInst();
+          auto inst = readInst(pos);
           if (auto* err = inst.getErr()) {
-            throwError(err->msg);
+            throwError(pos, err->msg);
           }
         }
         if (pos != endOfFunction) {
-          throwError("function overflowed its bounds");
+          throwError(pos, "function overflowed its bounds");
         }
         if (!builder.empty()) {
-          throwError("expected function end");
+          throwError(pos, "expected function end");
         }
       }
     }
@@ -2850,19 +2829,19 @@
   }
 }
 
-void WasmBinaryReader::readVars() {
+void WasmBinaryReader::readVars(size_t& pos) {
   uint32_t totalVars = 0;
-  size_t numLocalTypes = getU32LEB();
+  size_t numLocalTypes = getU32LEB(pos);
   // Use a SmallVector as in the common (MVP) case there are only 4 possible
   // types.
   SmallVector<std::pair<uint32_t, Type>, 4> decodedVars;
   decodedVars.reserve(numLocalTypes);
   for (size_t t = 0; t < numLocalTypes; t++) {
-    auto num = getU32LEB();
+    auto num = getU32LEB(pos);
     if (std::ckd_add(&totalVars, totalVars, num)) {
-      throwError("unaddressable number of locals");
+      throwError(pos, "unaddressable number of locals");
     }
-    auto type = getConcreteType();
+    auto type = getConcreteType(pos);
     decodedVars.emplace_back(num, type);
   }
   currFunction->vars.reserve(totalVars);
@@ -2874,58 +2853,58 @@
   }
 }
 
-Result<> WasmBinaryReader::readInst() {
+Result<> WasmBinaryReader::readInst(size_t& pos) {
   if (auto loc = sourceMapReader.readDebugLocationAt(pos)) {
     builder.setDebugLocation(loc);
   }
-  uint8_t code = getInt8();
+  uint8_t code = getInt8(pos);
   switch (code) {
     case BinaryConsts::Block:
-      return builder.makeBlock(Name(), getType());
+      return builder.makeBlock(Name(), getType(pos));
     case BinaryConsts::If:
-      return builder.makeIf(Name(), getType());
+      return builder.makeIf(Name(), getType(pos));
     case BinaryConsts::Loop:
-      return builder.makeLoop(Name(), getType());
+      return builder.makeLoop(Name(), getType(pos));
     case BinaryConsts::Br:
-      return builder.makeBreak(getU32LEB(), false);
+      return builder.makeBreak(getU32LEB(pos), false);
     case BinaryConsts::BrIf:
-      return builder.makeBreak(getU32LEB(), true);
+      return builder.makeBreak(getU32LEB(pos), true);
     case BinaryConsts::BrTable: {
-      auto numTargets = getU32LEB();
+      auto numTargets = getU32LEB(pos);
       std::vector<Index> labels(numTargets);
       for (Index i = 0; i < numTargets; ++i) {
-        labels[i] = getU32LEB();
+        labels[i] = getU32LEB(pos);
       }
-      return builder.makeSwitch(labels, getU32LEB());
+      return builder.makeSwitch(labels, getU32LEB(pos));
     }
     case BinaryConsts::CallFunction:
     case BinaryConsts::RetCallFunction:
-      return builder.makeCall(getFunctionName(getU32LEB()),
+      return builder.makeCall(getFunctionName(pos, getU32LEB(pos)),
                               code == BinaryConsts::RetCallFunction);
     case BinaryConsts::CallIndirect:
     case BinaryConsts::RetCallIndirect: {
-      auto type = getIndexedHeapType();
-      auto table = getTableName(getU32LEB());
+      auto type = getIndexedHeapType(pos);
+      auto table = getTableName(pos, getU32LEB(pos));
       return builder.makeCallIndirect(
         table, type, code == BinaryConsts::RetCallIndirect);
     }
     case BinaryConsts::LocalGet:
-      return builder.makeLocalGet(getU32LEB());
+      return builder.makeLocalGet(getU32LEB(pos));
     case BinaryConsts::LocalSet:
-      return builder.makeLocalSet(getU32LEB());
+      return builder.makeLocalSet(getU32LEB(pos));
     case BinaryConsts::LocalTee:
-      return builder.makeLocalTee(getU32LEB());
+      return builder.makeLocalTee(getU32LEB(pos));
     case BinaryConsts::GlobalGet:
-      return builder.makeGlobalGet(getGlobalName(getU32LEB()));
+      return builder.makeGlobalGet(getGlobalName(pos, getU32LEB(pos)));
     case BinaryConsts::GlobalSet:
-      return builder.makeGlobalSet(getGlobalName(getU32LEB()));
+      return builder.makeGlobalSet(getGlobalName(pos, getU32LEB(pos)));
     case BinaryConsts::Select:
       return builder.makeSelect(std::nullopt);
     case BinaryConsts::SelectWithType: {
-      auto numTypes = getU32LEB();
+      auto numTypes = getU32LEB(pos);
       std::vector<Type> types;
       for (Index i = 0; i < numTypes; ++i) {
-        auto t = getType();
+        auto t = getType(pos);
         if (!t.isConcrete()) {
           return Err{"bad select type"};
         }
@@ -2946,84 +2925,84 @@
     case BinaryConsts::Else:
       return builder.visitElse();
     case BinaryConsts::Catch_Legacy:
-      return builder.visitCatch(getTagName(getU32LEB()));
+      return builder.visitCatch(getTagName(pos, getU32LEB(pos)));
     case BinaryConsts::CatchAll_Legacy:
       return builder.visitCatchAll();
     case BinaryConsts::Delegate:
-      return builder.visitDelegate(getU32LEB());
+      return builder.visitDelegate(getU32LEB(pos));
     case BinaryConsts::RefNull:
-      return builder.makeRefNull(getHeapType());
+      return builder.makeRefNull(getHeapType(pos));
     case BinaryConsts::RefIsNull:
       return builder.makeRefIsNull();
     case BinaryConsts::RefFunc:
-      return builder.makeRefFunc(getFunctionName(getU32LEB()));
+      return builder.makeRefFunc(getFunctionName(pos, getU32LEB(pos)));
     case BinaryConsts::RefEq:
       return builder.makeRefEq();
     case BinaryConsts::RefAsNonNull:
       return builder.makeRefAs(RefAsNonNull);
     case BinaryConsts::BrOnNull:
-      return builder.makeBrOn(getU32LEB(), BrOnNull);
+      return builder.makeBrOn(getU32LEB(pos), BrOnNull);
     case BinaryConsts::BrOnNonNull:
-      return builder.makeBrOn(getU32LEB(), BrOnNonNull);
+      return builder.makeBrOn(getU32LEB(pos), BrOnNonNull);
     case BinaryConsts::TableGet:
-      return builder.makeTableGet(getTableName(getU32LEB()));
+      return builder.makeTableGet(getTableName(pos, getU32LEB(pos)));
     case BinaryConsts::TableSet:
-      return builder.makeTableSet(getTableName(getU32LEB()));
+      return builder.makeTableSet(getTableName(pos, getU32LEB(pos)));
     case BinaryConsts::Try:
-      return builder.makeTry(Name(), getType());
+      return builder.makeTry(Name(), getType(pos));
     case BinaryConsts::TryTable: {
-      auto type = getType();
+      auto type = getType(pos);
       std::vector<Name> tags;
       std::vector<Index> labels;
       std::vector<bool> isRefs;
-      auto numHandlers = getU32LEB();
+      auto numHandlers = getU32LEB(pos);
       for (Index i = 0; i < numHandlers; ++i) {
-        uint8_t code = getInt8();
+        uint8_t code = getInt8(pos);
         if (code == BinaryConsts::Catch || code == BinaryConsts::CatchRef) {
-          tags.push_back(getTagName(getU32LEB()));
+          tags.push_back(getTagName(pos, getU32LEB(pos)));
         } else {
           tags.push_back(Name());
         }
-        labels.push_back(getU32LEB());
+        labels.push_back(getU32LEB(pos));
         isRefs.push_back(code == BinaryConsts::CatchRef ||
                          code == BinaryConsts::CatchAllRef);
       }
       return builder.makeTryTable(Name(), type, tags, labels, isRefs);
     }
     case BinaryConsts::Throw:
-      return builder.makeThrow(getTagName(getU32LEB()));
+      return builder.makeThrow(getTagName(pos, getU32LEB(pos)));
     case BinaryConsts::Rethrow:
-      return builder.makeRethrow(getU32LEB());
+      return builder.makeRethrow(getU32LEB(pos));
     case BinaryConsts::ThrowRef:
       return builder.makeThrowRef();
     case BinaryConsts::MemorySize:
-      return builder.makeMemorySize(getMemoryName(getU32LEB()));
+      return builder.makeMemorySize(getMemoryName(pos, getU32LEB(pos)));
     case BinaryConsts::MemoryGrow:
-      return builder.makeMemoryGrow(getMemoryName(getU32LEB()));
+      return builder.makeMemoryGrow(getMemoryName(pos, getU32LEB(pos)));
     case BinaryConsts::CallRef:
     case BinaryConsts::RetCallRef:
-      return builder.makeCallRef(getIndexedHeapType(),
+      return builder.makeCallRef(getIndexedHeapType(pos),
                                  code == BinaryConsts::RetCallRef);
     case BinaryConsts::ContBind: {
-      auto before = getIndexedHeapType();
-      auto after = getIndexedHeapType();
+      auto before = getIndexedHeapType(pos);
+      auto after = getIndexedHeapType(pos);
       return builder.makeContBind(before, after);
     }
     case BinaryConsts::ContNew:
-      return builder.makeContNew(getIndexedHeapType());
+      return builder.makeContNew(getIndexedHeapType(pos));
     case BinaryConsts::Resume: {
-      auto type = getIndexedHeapType();
+      auto type = getIndexedHeapType(pos);
       std::vector<Name> tags;
       std::vector<Index> labels;
-      auto numHandlers = getU32LEB();
+      auto numHandlers = getU32LEB(pos);
       for (Index i = 0; i < numHandlers; ++i) {
-        tags.push_back(getTagName(getU32LEB()));
-        labels.push_back(getU32LEB());
+        tags.push_back(getTagName(pos, getU32LEB(pos)));
+        labels.push_back(getU32LEB(pos));
       }
       return builder.makeResume(type, tags, labels);
     }
     case BinaryConsts::Suspend:
-      return builder.makeSuspend(getTagName(getU32LEB()));
+      return builder.makeSuspend(getTagName(pos, getU32LEB(pos)));
 
 #define BINARY_INT(code)                                                       \
   case BinaryConsts::I32##code:                                                \
@@ -3160,193 +3139,193 @@
     case BinaryConsts::I64ExtendS32:
       return builder.makeUnary(ExtendS32Int64);
     case BinaryConsts::I32Const:
-      return builder.makeConst(Literal(getS32LEB()));
+      return builder.makeConst(Literal(getS32LEB(pos)));
     case BinaryConsts::I64Const:
-      return builder.makeConst(Literal(getS64LEB()));
+      return builder.makeConst(Literal(getS64LEB(pos)));
     case BinaryConsts::F32Const:
-      return builder.makeConst(getFloat32Literal());
+      return builder.makeConst(getFloat32Literal(pos));
     case BinaryConsts::F64Const:
-      return builder.makeConst(getFloat64Literal());
+      return builder.makeConst(getFloat64Literal(pos));
     case BinaryConsts::I32LoadMem8S: {
-      auto [mem, align, offset] = getMemarg();
+      auto [mem, align, offset] = getMemarg(pos);
       return builder.makeLoad(1, true, offset, align, Type::i32, mem);
     }
     case BinaryConsts::I32LoadMem8U: {
-      auto [mem, align, offset] = getMemarg();
+      auto [mem, align, offset] = getMemarg(pos);
       return builder.makeLoad(1, false, offset, align, Type::i32, mem);
     }
     case BinaryConsts::I32LoadMem16S: {
-      auto [mem, align, offset] = getMemarg();
+      auto [mem, align, offset] = getMemarg(pos);
       return builder.makeLoad(2, true, offset, align, Type::i32, mem);
     }
     case BinaryConsts::I32LoadMem16U: {
-      auto [mem, align, offset] = getMemarg();
+      auto [mem, align, offset] = getMemarg(pos);
       return builder.makeLoad(2, false, offset, align, Type::i32, mem);
     }
     case BinaryConsts::I32LoadMem: {
-      auto [mem, align, offset] = getMemarg();
+      auto [mem, align, offset] = getMemarg(pos);
       return builder.makeLoad(4, false, offset, align, Type::i32, mem);
     }
     case BinaryConsts::I64LoadMem8S: {
-      auto [mem, align, offset] = getMemarg();
+      auto [mem, align, offset] = getMemarg(pos);
       return builder.makeLoad(1, true, offset, align, Type::i64, mem);
     }
     case BinaryConsts::I64LoadMem8U: {
-      auto [mem, align, offset] = getMemarg();
+      auto [mem, align, offset] = getMemarg(pos);
       return builder.makeLoad(1, false, offset, align, Type::i64, mem);
     }
     case BinaryConsts::I64LoadMem16S: {
-      auto [mem, align, offset] = getMemarg();
+      auto [mem, align, offset] = getMemarg(pos);
       return builder.makeLoad(2, true, offset, align, Type::i64, mem);
     }
     case BinaryConsts::I64LoadMem16U: {
-      auto [mem, align, offset] = getMemarg();
+      auto [mem, align, offset] = getMemarg(pos);
       return builder.makeLoad(2, false, offset, align, Type::i64, mem);
     }
     case BinaryConsts::I64LoadMem32S: {
-      auto [mem, align, offset] = getMemarg();
+      auto [mem, align, offset] = getMemarg(pos);
       return builder.makeLoad(4, true, offset, align, Type::i64, mem);
     }
     case BinaryConsts::I64LoadMem32U: {
-      auto [mem, align, offset] = getMemarg();
+      auto [mem, align, offset] = getMemarg(pos);
       return builder.makeLoad(4, false, offset, align, Type::i64, mem);
     }
     case BinaryConsts::I64LoadMem: {
-      auto [mem, align, offset] = getMemarg();
+      auto [mem, align, offset] = getMemarg(pos);
       return builder.makeLoad(8, false, offset, align, Type::i64, mem);
     }
     case BinaryConsts::F32LoadMem: {
-      auto [mem, align, offset] = getMemarg();
+      auto [mem, align, offset] = getMemarg(pos);
       return builder.makeLoad(4, false, offset, align, Type::f32, mem);
     }
     case BinaryConsts::F64LoadMem: {
-      auto [mem, align, offset] = getMemarg();
+      auto [mem, align, offset] = getMemarg(pos);
       return builder.makeLoad(8, false, offset, align, Type::f64, mem);
     }
     case BinaryConsts::I32StoreMem8: {
-      auto [mem, align, offset] = getMemarg();
+      auto [mem, align, offset] = getMemarg(pos);
       return builder.makeStore(1, offset, align, Type::i32, mem);
     }
     case BinaryConsts::I32StoreMem16: {
-      auto [mem, align, offset] = getMemarg();
+      auto [mem, align, offset] = getMemarg(pos);
       return builder.makeStore(2, offset, align, Type::i32, mem);
     }
     case BinaryConsts::I32StoreMem: {
-      auto [mem, align, offset] = getMemarg();
+      auto [mem, align, offset] = getMemarg(pos);
       return builder.makeStore(4, offset, align, Type::i32, mem);
     }
     case BinaryConsts::I64StoreMem8: {
-      auto [mem, align, offset] = getMemarg();
+      auto [mem, align, offset] = getMemarg(pos);
       return builder.makeStore(1, offset, align, Type::i64, mem);
     }
     case BinaryConsts::I64StoreMem16: {
-      auto [mem, align, offset] = getMemarg();
+      auto [mem, align, offset] = getMemarg(pos);
       return builder.makeStore(2, offset, align, Type::i64, mem);
     }
     case BinaryConsts::I64StoreMem32: {
-      auto [mem, align, offset] = getMemarg();
+      auto [mem, align, offset] = getMemarg(pos);
       return builder.makeStore(4, offset, align, Type::i64, mem);
     }
     case BinaryConsts::I64StoreMem: {
-      auto [mem, align, offset] = getMemarg();
+      auto [mem, align, offset] = getMemarg(pos);
       return builder.makeStore(8, offset, align, Type::i64, mem);
     }
     case BinaryConsts::F32StoreMem: {
-      auto [mem, align, offset] = getMemarg();
+      auto [mem, align, offset] = getMemarg(pos);
       return builder.makeStore(4, offset, align, Type::f32, mem);
     }
     case BinaryConsts::F64StoreMem: {
-      auto [mem, align, offset] = getMemarg();
+      auto [mem, align, offset] = getMemarg(pos);
       return builder.makeStore(8, offset, align, Type::f64, mem);
     }
     case BinaryConsts::AtomicPrefix: {
-      auto op = getU32LEB();
+      auto op = getU32LEB(pos);
       switch (op) {
         case BinaryConsts::I32AtomicLoad8U: {
           // TODO: pass align through for validation.
-          auto [mem, align, offset] = getMemarg();
+          auto [mem, align, offset] = getMemarg(pos);
           return builder.makeAtomicLoad(1, offset, Type::i32, mem);
         }
         case BinaryConsts::I32AtomicLoad16U: {
-          auto [mem, align, offset] = getMemarg();
+          auto [mem, align, offset] = getMemarg(pos);
           return builder.makeAtomicLoad(2, offset, Type::i32, mem);
         }
         case BinaryConsts::I32AtomicLoad: {
-          auto [mem, align, offset] = getMemarg();
+          auto [mem, align, offset] = getMemarg(pos);
           return builder.makeAtomicLoad(4, offset, Type::i32, mem);
         }
         case BinaryConsts::I64AtomicLoad8U: {
-          auto [mem, align, offset] = getMemarg();
+          auto [mem, align, offset] = getMemarg(pos);
           return builder.makeAtomicLoad(1, offset, Type::i64, mem);
         }
         case BinaryConsts::I64AtomicLoad16U: {
-          auto [mem, align, offset] = getMemarg();
+          auto [mem, align, offset] = getMemarg(pos);
           return builder.makeAtomicLoad(2, offset, Type::i64, mem);
         }
         case BinaryConsts::I64AtomicLoad32U: {
-          auto [mem, align, offset] = getMemarg();
+          auto [mem, align, offset] = getMemarg(pos);
           return builder.makeAtomicLoad(4, offset, Type::i64, mem);
         }
         case BinaryConsts::I64AtomicLoad: {
-          auto [mem, align, offset] = getMemarg();
+          auto [mem, align, offset] = getMemarg(pos);
           return builder.makeAtomicLoad(8, offset, Type::i64, mem);
         }
         case BinaryConsts::I32AtomicStore8: {
-          auto [mem, align, offset] = getMemarg();
+          auto [mem, align, offset] = getMemarg(pos);
           return builder.makeAtomicStore(1, offset, Type::i32, mem);
         }
         case BinaryConsts::I32AtomicStore16: {
-          auto [mem, align, offset] = getMemarg();
+          auto [mem, align, offset] = getMemarg(pos);
           return builder.makeAtomicStore(2, offset, Type::i32, mem);
         }
         case BinaryConsts::I32AtomicStore: {
-          auto [mem, align, offset] = getMemarg();
+          auto [mem, align, offset] = getMemarg(pos);
           return builder.makeAtomicStore(4, offset, Type::i32, mem);
         }
         case BinaryConsts::I64AtomicStore8: {
-          auto [mem, align, offset] = getMemarg();
+          auto [mem, align, offset] = getMemarg(pos);
           return builder.makeAtomicStore(1, offset, Type::i64, mem);
         }
         case BinaryConsts::I64AtomicStore16: {
-          auto [mem, align, offset] = getMemarg();
+          auto [mem, align, offset] = getMemarg(pos);
           return builder.makeAtomicStore(2, offset, Type::i64, mem);
         }
         case BinaryConsts::I64AtomicStore32: {
-          auto [mem, align, offset] = getMemarg();
+          auto [mem, align, offset] = getMemarg(pos);
           return builder.makeAtomicStore(4, offset, Type::i64, mem);
         }
         case BinaryConsts::I64AtomicStore: {
-          auto [mem, align, offset] = getMemarg();
+          auto [mem, align, offset] = getMemarg(pos);
           return builder.makeAtomicStore(8, offset, Type::i64, mem);
         }
 
 #define RMW(op)                                                                \
   case BinaryConsts::I32AtomicRMW##op: {                                       \
-    auto [mem, align, offset] = getMemarg();                                   \
+    auto [mem, align, offset] = getMemarg(pos);                                \
     return builder.makeAtomicRMW(RMW##op, 4, offset, Type::i32, mem);          \
   }                                                                            \
   case BinaryConsts::I32AtomicRMW##op##8U: {                                   \
-    auto [mem, align, offset] = getMemarg();                                   \
+    auto [mem, align, offset] = getMemarg(pos);                                \
     return builder.makeAtomicRMW(RMW##op, 1, offset, Type::i32, mem);          \
   }                                                                            \
   case BinaryConsts::I32AtomicRMW##op##16U: {                                  \
-    auto [mem, align, offset] = getMemarg();                                   \
+    auto [mem, align, offset] = getMemarg(pos);                                \
     return builder.makeAtomicRMW(RMW##op, 2, offset, Type::i32, mem);          \
   }                                                                            \
   case BinaryConsts::I64AtomicRMW##op: {                                       \
-    auto [mem, align, offset] = getMemarg();                                   \
+    auto [mem, align, offset] = getMemarg(pos);                                \
     return builder.makeAtomicRMW(RMW##op, 8, offset, Type::i64, mem);          \
   }                                                                            \
   case BinaryConsts::I64AtomicRMW##op##8U: {                                   \
-    auto [mem, align, offset] = getMemarg();                                   \
+    auto [mem, align, offset] = getMemarg(pos);                                \
     return builder.makeAtomicRMW(RMW##op, 1, offset, Type::i64, mem);          \
   }                                                                            \
   case BinaryConsts::I64AtomicRMW##op##16U: {                                  \
-    auto [mem, align, offset] = getMemarg();                                   \
+    auto [mem, align, offset] = getMemarg(pos);                                \
     return builder.makeAtomicRMW(RMW##op, 2, offset, Type::i64, mem);          \
   }                                                                            \
   case BinaryConsts::I64AtomicRMW##op##32U: {                                  \
-    auto [mem, align, offset] = getMemarg();                                   \
+    auto [mem, align, offset] = getMemarg(pos);                                \
     return builder.makeAtomicRMW(RMW##op, 4, offset, Type::i64, mem);          \
   }
 
@@ -3358,47 +3337,47 @@
           RMW(Xchg);
 
         case BinaryConsts::I32AtomicCmpxchg: {
-          auto [mem, align, offset] = getMemarg();
+          auto [mem, align, offset] = getMemarg(pos);
           return builder.makeAtomicCmpxchg(4, offset, Type::i32, mem);
         }
         case BinaryConsts::I32AtomicCmpxchg8U: {
-          auto [mem, align, offset] = getMemarg();
+          auto [mem, align, offset] = getMemarg(pos);
           return builder.makeAtomicCmpxchg(1, offset, Type::i32, mem);
         }
         case BinaryConsts::I32AtomicCmpxchg16U: {
-          auto [mem, align, offset] = getMemarg();
+          auto [mem, align, offset] = getMemarg(pos);
           return builder.makeAtomicCmpxchg(2, offset, Type::i32, mem);
         }
         case BinaryConsts::I64AtomicCmpxchg: {
-          auto [mem, align, offset] = getMemarg();
+          auto [mem, align, offset] = getMemarg(pos);
           return builder.makeAtomicCmpxchg(8, offset, Type::i64, mem);
         }
         case BinaryConsts::I64AtomicCmpxchg8U: {
-          auto [mem, align, offset] = getMemarg();
+          auto [mem, align, offset] = getMemarg(pos);
           return builder.makeAtomicCmpxchg(1, offset, Type::i64, mem);
         }
         case BinaryConsts::I64AtomicCmpxchg16U: {
-          auto [mem, align, offset] = getMemarg();
+          auto [mem, align, offset] = getMemarg(pos);
           return builder.makeAtomicCmpxchg(2, offset, Type::i64, mem);
         }
         case BinaryConsts::I64AtomicCmpxchg32U: {
-          auto [mem, align, offset] = getMemarg();
+          auto [mem, align, offset] = getMemarg(pos);
           return builder.makeAtomicCmpxchg(4, offset, Type::i64, mem);
         }
         case BinaryConsts::I32AtomicWait: {
-          auto [mem, align, offset] = getMemarg();
+          auto [mem, align, offset] = getMemarg(pos);
           return builder.makeAtomicWait(Type::i32, offset, mem);
         }
         case BinaryConsts::I64AtomicWait: {
-          auto [mem, align, offset] = getMemarg();
+          auto [mem, align, offset] = getMemarg(pos);
           return builder.makeAtomicWait(Type::i64, offset, mem);
         }
         case BinaryConsts::AtomicNotify: {
-          auto [mem, align, offset] = getMemarg();
+          auto [mem, align, offset] = getMemarg(pos);
           return builder.makeAtomicNotify(offset, mem);
         }
         case BinaryConsts::AtomicFence:
-          if (getInt8() != 0) {
+          if (getInt8(pos) != 0) {
             return Err{"expected 0x00 byte immediate on atomic.fence"};
           }
           return builder.makeAtomicFence();
@@ -3406,7 +3385,7 @@
       return Err{"unknown atomic operation"};
     }
     case BinaryConsts::MiscPrefix: {
-      auto op = getU32LEB();
+      auto op = getU32LEB(pos);
       switch (op) {
         case BinaryConsts::I32STruncSatF32:
           return builder.makeUnary(TruncSatSFloat32ToInt32);
@@ -3425,48 +3404,48 @@
         case BinaryConsts::I64UTruncSatF64:
           return builder.makeUnary(TruncSatUFloat64ToInt64);
         case BinaryConsts::MemoryInit: {
-          auto data = getDataName(getU32LEB());
-          auto mem = getMemoryName(getU32LEB());
+          auto data = getDataName(pos, getU32LEB(pos));
+          auto mem = getMemoryName(pos, getU32LEB(pos));
           return builder.makeMemoryInit(data, mem);
         }
         case BinaryConsts::DataDrop:
-          return builder.makeDataDrop(getDataName(getU32LEB()));
+          return builder.makeDataDrop(getDataName(pos, getU32LEB(pos)));
         case BinaryConsts::MemoryCopy: {
-          auto dest = getMemoryName(getU32LEB());
-          auto src = getMemoryName(getU32LEB());
+          auto dest = getMemoryName(pos, getU32LEB(pos));
+          auto src = getMemoryName(pos, getU32LEB(pos));
           return builder.makeMemoryCopy(dest, src);
         }
         case BinaryConsts::MemoryFill:
-          return builder.makeMemoryFill(getMemoryName(getU32LEB()));
+          return builder.makeMemoryFill(getMemoryName(pos, getU32LEB(pos)));
         case BinaryConsts::TableSize:
-          return builder.makeTableSize(getTableName(getU32LEB()));
+          return builder.makeTableSize(getTableName(pos, getU32LEB(pos)));
         case BinaryConsts::TableGrow:
-          return builder.makeTableGrow(getTableName(getU32LEB()));
+          return builder.makeTableGrow(getTableName(pos, getU32LEB(pos)));
         case BinaryConsts::TableFill:
-          return builder.makeTableFill(getTableName(getU32LEB()));
+          return builder.makeTableFill(getTableName(pos, getU32LEB(pos)));
         case BinaryConsts::TableCopy: {
-          auto dest = getTableName(getU32LEB());
-          auto src = getTableName(getU32LEB());
+          auto dest = getTableName(pos, getU32LEB(pos));
+          auto src = getTableName(pos, getU32LEB(pos));
           return builder.makeTableCopy(dest, src);
         }
         case BinaryConsts::TableInit: {
-          auto elem = getElemName(getU32LEB());
-          auto table = getTableName(getU32LEB());
+          auto elem = getElemName(pos, getU32LEB(pos));
+          auto table = getTableName(pos, getU32LEB(pos));
           return builder.makeTableInit(elem, table);
         }
         case BinaryConsts::F32_F16LoadMem: {
-          auto [mem, align, offset] = getMemarg();
+          auto [mem, align, offset] = getMemarg(pos);
           return builder.makeLoad(2, false, offset, align, Type::f32, mem);
         }
         case BinaryConsts::F32_F16StoreMem: {
-          auto [mem, align, offset] = getMemarg();
+          auto [mem, align, offset] = getMemarg(pos);
           return builder.makeStore(2, offset, align, Type::f32, mem);
         }
       }
       return Err{"unknown misc operation"};
     }
     case BinaryConsts::SIMDPrefix: {
-      auto op = getU32LEB();
+      auto op = getU32LEB(pos);
       switch (op) {
         case BinaryConsts::I8x16Eq:
           return builder.makeBinary(EqVecI8x16);
@@ -3914,42 +3893,56 @@
           return builder.makeUnary(ConvertUVecI16x8ToVecF16x8);
         case BinaryConsts::I8x16ExtractLaneS:
           return builder.makeSIMDExtract(ExtractLaneSVecI8x16,
-                                         getLaneIndex(16));
+                                         getLaneIndex(pos, 16));
         case BinaryConsts::I8x16ExtractLaneU:
           return builder.makeSIMDExtract(ExtractLaneUVecI8x16,
-                                         getLaneIndex(16));
+                                         getLaneIndex(pos, 16));
         case BinaryConsts::I16x8ExtractLaneS:
-          return builder.makeSIMDExtract(ExtractLaneSVecI16x8, getLaneIndex(8));
+          return builder.makeSIMDExtract(ExtractLaneSVecI16x8,
+                                         getLaneIndex(pos, 8));
         case BinaryConsts::I16x8ExtractLaneU:
-          return builder.makeSIMDExtract(ExtractLaneUVecI16x8, getLaneIndex(8));
+          return builder.makeSIMDExtract(ExtractLaneUVecI16x8,
+                                         getLaneIndex(pos, 8));
         case BinaryConsts::I32x4ExtractLane:
-          return builder.makeSIMDExtract(ExtractLaneVecI32x4, getLaneIndex(4));
+          return builder.makeSIMDExtract(ExtractLaneVecI32x4,
+                                         getLaneIndex(pos, 4));
         case BinaryConsts::I64x2ExtractLane:
-          return builder.makeSIMDExtract(ExtractLaneVecI64x2, getLaneIndex(2));
+          return builder.makeSIMDExtract(ExtractLaneVecI64x2,
+                                         getLaneIndex(pos, 2));
         case BinaryConsts::F16x8ExtractLane:
-          return builder.makeSIMDExtract(ExtractLaneVecF16x8, getLaneIndex(8));
+          return builder.makeSIMDExtract(ExtractLaneVecF16x8,
+                                         getLaneIndex(pos, 8));
         case BinaryConsts::F32x4ExtractLane:
-          return builder.makeSIMDExtract(ExtractLaneVecF32x4, getLaneIndex(4));
+          return builder.makeSIMDExtract(ExtractLaneVecF32x4,
+                                         getLaneIndex(pos, 4));
         case BinaryConsts::F64x2ExtractLane:
-          return builder.makeSIMDExtract(ExtractLaneVecF64x2, getLaneIndex(2));
+          return builder.makeSIMDExtract(ExtractLaneVecF64x2,
+                                         getLaneIndex(pos, 2));
         case BinaryConsts::I8x16ReplaceLane:
-          return builder.makeSIMDReplace(ReplaceLaneVecI8x16, getLaneIndex(16));
+          return builder.makeSIMDReplace(ReplaceLaneVecI8x16,
+                                         getLaneIndex(pos, 16));
         case BinaryConsts::I16x8ReplaceLane:
-          return builder.makeSIMDReplace(ReplaceLaneVecI16x8, getLaneIndex(8));
+          return builder.makeSIMDReplace(ReplaceLaneVecI16x8,
+                                         getLaneIndex(pos, 8));
         case BinaryConsts::I32x4ReplaceLane:
-          return builder.makeSIMDReplace(ReplaceLaneVecI32x4, getLaneIndex(4));
+          return builder.makeSIMDReplace(ReplaceLaneVecI32x4,
+                                         getLaneIndex(pos, 4));
         case BinaryConsts::I64x2ReplaceLane:
-          return builder.makeSIMDReplace(ReplaceLaneVecI64x2, getLaneIndex(2));
+          return builder.makeSIMDReplace(ReplaceLaneVecI64x2,
+                                         getLaneIndex(pos, 2));
         case BinaryConsts::F16x8ReplaceLane:
-          return builder.makeSIMDReplace(ReplaceLaneVecF16x8, getLaneIndex(8));
+          return builder.makeSIMDReplace(ReplaceLaneVecF16x8,
+                                         getLaneIndex(pos, 8));
         case BinaryConsts::F32x4ReplaceLane:
-          return builder.makeSIMDReplace(ReplaceLaneVecF32x4, getLaneIndex(4));
+          return builder.makeSIMDReplace(ReplaceLaneVecF32x4,
+                                         getLaneIndex(pos, 4));
         case BinaryConsts::F64x2ReplaceLane:
-          return builder.makeSIMDReplace(ReplaceLaneVecF64x2, getLaneIndex(2));
+          return builder.makeSIMDReplace(ReplaceLaneVecF64x2,
+                                         getLaneIndex(pos, 2));
         case BinaryConsts::I8x16Shuffle: {
           std::array<uint8_t, 16> lanes;
           for (Index i = 0; i < 16; ++i) {
-            lanes[i] = getLaneIndex(32);
+            lanes[i] = getLaneIndex(pos, 32);
           }
           return builder.makeSIMDShuffle(lanes);
         }
@@ -4002,108 +3995,108 @@
         case BinaryConsts::I64x2ShrU:
           return builder.makeSIMDShift(ShrUVecI64x2);
         case BinaryConsts::V128Const:
-          return builder.makeConst(getVec128Literal());
+          return builder.makeConst(getVec128Literal(pos));
         case BinaryConsts::V128Store: {
-          auto [mem, align, offset] = getMemarg();
+          auto [mem, align, offset] = getMemarg(pos);
           return builder.makeStore(16, offset, align, Type::v128, mem);
         }
         case BinaryConsts::V128Load: {
-          auto [mem, align, offset] = getMemarg();
+          auto [mem, align, offset] = getMemarg(pos);
           return builder.makeLoad(16, false, offset, align, Type::v128, mem);
         }
         case BinaryConsts::V128Load8Splat: {
-          auto [mem, align, offset] = getMemarg();
+          auto [mem, align, offset] = getMemarg(pos);
           return builder.makeSIMDLoad(Load8SplatVec128, offset, align, mem);
         }
         case BinaryConsts::V128Load16Splat: {
-          auto [mem, align, offset] = getMemarg();
+          auto [mem, align, offset] = getMemarg(pos);
           return builder.makeSIMDLoad(Load16SplatVec128, offset, align, mem);
         }
         case BinaryConsts::V128Load32Splat: {
-          auto [mem, align, offset] = getMemarg();
+          auto [mem, align, offset] = getMemarg(pos);
           return builder.makeSIMDLoad(Load32SplatVec128, offset, align, mem);
         }
         case BinaryConsts::V128Load64Splat: {
-          auto [mem, align, offset] = getMemarg();
+          auto [mem, align, offset] = getMemarg(pos);
           return builder.makeSIMDLoad(Load64SplatVec128, offset, align, mem);
         }
         case BinaryConsts::V128Load8x8S: {
-          auto [mem, align, offset] = getMemarg();
+          auto [mem, align, offset] = getMemarg(pos);
           return builder.makeSIMDLoad(Load8x8SVec128, offset, align, mem);
         }
         case BinaryConsts::V128Load8x8U: {
-          auto [mem, align, offset] = getMemarg();
+          auto [mem, align, offset] = getMemarg(pos);
           return builder.makeSIMDLoad(Load8x8UVec128, offset, align, mem);
         }
         case BinaryConsts::V128Load16x4S: {
-          auto [mem, align, offset] = getMemarg();
+          auto [mem, align, offset] = getMemarg(pos);
           return builder.makeSIMDLoad(Load16x4SVec128, offset, align, mem);
         }
         case BinaryConsts::V128Load16x4U: {
-          auto [mem, align, offset] = getMemarg();
+          auto [mem, align, offset] = getMemarg(pos);
           return builder.makeSIMDLoad(Load16x4UVec128, offset, align, mem);
         }
         case BinaryConsts::V128Load32x2S: {
-          auto [mem, align, offset] = getMemarg();
+          auto [mem, align, offset] = getMemarg(pos);
           return builder.makeSIMDLoad(Load32x2SVec128, offset, align, mem);
         }
         case BinaryConsts::V128Load32x2U: {
-          auto [mem, align, offset] = getMemarg();
+          auto [mem, align, offset] = getMemarg(pos);
           return builder.makeSIMDLoad(Load32x2UVec128, offset, align, mem);
         }
         case BinaryConsts::V128Load32Zero: {
-          auto [mem, align, offset] = getMemarg();
+          auto [mem, align, offset] = getMemarg(pos);
           return builder.makeSIMDLoad(Load32ZeroVec128, offset, align, mem);
         }
         case BinaryConsts::V128Load64Zero: {
-          auto [mem, align, offset] = getMemarg();
+          auto [mem, align, offset] = getMemarg(pos);
           return builder.makeSIMDLoad(Load64ZeroVec128, offset, align, mem);
         }
         case BinaryConsts::V128Load8Lane: {
-          auto [mem, align, offset] = getMemarg();
+          auto [mem, align, offset] = getMemarg(pos);
           return builder.makeSIMDLoadStoreLane(
-            Load8LaneVec128, offset, align, getLaneIndex(16), mem);
+            Load8LaneVec128, offset, align, getLaneIndex(pos, 16), mem);
         }
         case BinaryConsts::V128Load16Lane: {
-          auto [mem, align, offset] = getMemarg();
+          auto [mem, align, offset] = getMemarg(pos);
           return builder.makeSIMDLoadStoreLane(
-            Load16LaneVec128, offset, align, getLaneIndex(8), mem);
+            Load16LaneVec128, offset, align, getLaneIndex(pos, 8), mem);
         }
         case BinaryConsts::V128Load32Lane: {
-          auto [mem, align, offset] = getMemarg();
+          auto [mem, align, offset] = getMemarg(pos);
           return builder.makeSIMDLoadStoreLane(
-            Load32LaneVec128, offset, align, getLaneIndex(4), mem);
+            Load32LaneVec128, offset, align, getLaneIndex(pos, 4), mem);
         }
         case BinaryConsts::V128Load64Lane: {
-          auto [mem, align, offset] = getMemarg();
+          auto [mem, align, offset] = getMemarg(pos);
           return builder.makeSIMDLoadStoreLane(
-            Load64LaneVec128, offset, align, getLaneIndex(2), mem);
+            Load64LaneVec128, offset, align, getLaneIndex(pos, 2), mem);
         }
         case BinaryConsts::V128Store8Lane: {
-          auto [mem, align, offset] = getMemarg();
+          auto [mem, align, offset] = getMemarg(pos);
           return builder.makeSIMDLoadStoreLane(
-            Store8LaneVec128, offset, align, getLaneIndex(16), mem);
+            Store8LaneVec128, offset, align, getLaneIndex(pos, 16), mem);
         }
         case BinaryConsts::V128Store16Lane: {
-          auto [mem, align, offset] = getMemarg();
+          auto [mem, align, offset] = getMemarg(pos);
           return builder.makeSIMDLoadStoreLane(
-            Store16LaneVec128, offset, align, getLaneIndex(8), mem);
+            Store16LaneVec128, offset, align, getLaneIndex(pos, 8), mem);
         }
         case BinaryConsts::V128Store32Lane: {
-          auto [mem, align, offset] = getMemarg();
+          auto [mem, align, offset] = getMemarg(pos);
           return builder.makeSIMDLoadStoreLane(
-            Store32LaneVec128, offset, align, getLaneIndex(4), mem);
+            Store32LaneVec128, offset, align, getLaneIndex(pos, 4), mem);
         }
         case BinaryConsts::V128Store64Lane: {
-          auto [mem, align, offset] = getMemarg();
+          auto [mem, align, offset] = getMemarg(pos);
           return builder.makeSIMDLoadStoreLane(
-            Store64LaneVec128, offset, align, getLaneIndex(2), mem);
+            Store64LaneVec128, offset, align, getLaneIndex(pos, 2), mem);
         }
       }
       return Err{"unknown SIMD operation"};
     }
     case BinaryConsts::GCPrefix: {
-      auto op = getU32LEB();
+      auto op = getU32LEB(pos);
       switch (op) {
         case BinaryConsts::RefI31:
           return builder.makeRefI31(Unshared);
@@ -4114,82 +4107,84 @@
         case BinaryConsts::I31GetU:
           return builder.makeI31Get(false);
         case BinaryConsts::RefTest:
-          return builder.makeRefTest(Type(getHeapType(), NonNullable));
+          return builder.makeRefTest(Type(getHeapType(pos), NonNullable));
         case BinaryConsts::RefTestNull:
-          return builder.makeRefTest(Type(getHeapType(), Nullable));
+          return builder.makeRefTest(Type(getHeapType(pos), Nullable));
         case BinaryConsts::RefCast:
-          return builder.makeRefCast(Type(getHeapType(), NonNullable));
+          return builder.makeRefCast(Type(getHeapType(pos), NonNullable));
         case BinaryConsts::RefCastNull:
-          return builder.makeRefCast(Type(getHeapType(), Nullable));
+          return builder.makeRefCast(Type(getHeapType(pos), Nullable));
         case BinaryConsts::BrOnCast:
         case BinaryConsts::BrOnCastFail: {
-          auto flags = getInt8();
-          auto label = getU32LEB();
-          auto in = Type(getHeapType(), (flags & 1) ? Nullable : NonNullable);
-          auto cast = Type(getHeapType(), (flags & 2) ? Nullable : NonNullable);
+          auto flags = getInt8(pos);
+          auto label = getU32LEB(pos);
+          auto in =
+            Type(getHeapType(pos), (flags & 1) ? Nullable : NonNullable);
+          auto cast =
+            Type(getHeapType(pos), (flags & 2) ? Nullable : NonNullable);
           auto kind = op == BinaryConsts::BrOnCast ? BrOnCast : BrOnCastFail;
           return builder.makeBrOn(label, kind, in, cast);
         }
         case BinaryConsts::StructNew:
-          return builder.makeStructNew(getIndexedHeapType());
+          return builder.makeStructNew(getIndexedHeapType(pos));
         case BinaryConsts::StructNewDefault:
-          return builder.makeStructNewDefault(getIndexedHeapType());
+          return builder.makeStructNewDefault(getIndexedHeapType(pos));
         case BinaryConsts::StructGet:
         case BinaryConsts::StructGetS:
         case BinaryConsts::StructGetU: {
-          auto type = getIndexedHeapType();
-          auto field = getU32LEB();
+          auto type = getIndexedHeapType(pos);
+          auto field = getU32LEB(pos);
           return builder.makeStructGet(
             type, field, op == BinaryConsts::StructGetS);
         }
         case BinaryConsts::StructSet: {
-          auto type = getIndexedHeapType();
-          auto field = getU32LEB();
+          auto type = getIndexedHeapType(pos);
+          auto field = getU32LEB(pos);
           return builder.makeStructSet(type, field);
         }
         case BinaryConsts::ArrayNew:
-          return builder.makeArrayNew(getIndexedHeapType());
+          return builder.makeArrayNew(getIndexedHeapType(pos));
         case BinaryConsts::ArrayNewDefault:
-          return builder.makeArrayNewDefault(getIndexedHeapType());
+          return builder.makeArrayNewDefault(getIndexedHeapType(pos));
         case BinaryConsts::ArrayNewFixed: {
-          auto type = getIndexedHeapType();
-          auto arity = getU32LEB();
+          auto type = getIndexedHeapType(pos);
+          auto arity = getU32LEB(pos);
           return builder.makeArrayNewFixed(type, arity);
         }
         case BinaryConsts::ArrayNewData: {
-          auto type = getIndexedHeapType();
-          auto data = getDataName(getU32LEB());
+          auto type = getIndexedHeapType(pos);
+          auto data = getDataName(pos, getU32LEB(pos));
           return builder.makeArrayNewData(type, data);
         }
         case BinaryConsts::ArrayNewElem: {
-          auto type = getIndexedHeapType();
-          auto elem = getElemName(getU32LEB());
+          auto type = getIndexedHeapType(pos);
+          auto elem = getElemName(pos, getU32LEB(pos));
           return builder.makeArrayNewElem(type, elem);
         }
         case BinaryConsts::ArrayGet:
         case BinaryConsts::ArrayGetU:
-          return builder.makeArrayGet(getIndexedHeapType(), false);
+          return builder.makeArrayGet(getIndexedHeapType(pos), false);
         case BinaryConsts::ArrayGetS:
-          return builder.makeArrayGet(getIndexedHeapType(), true);
+          return builder.makeArrayGet(getIndexedHeapType(pos), true);
         case BinaryConsts::ArraySet:
-          return builder.makeArraySet(getIndexedHeapType());
+          return builder.makeArraySet(getIndexedHeapType(pos));
         case BinaryConsts::ArrayLen:
           return builder.makeArrayLen();
         case BinaryConsts::ArrayCopy: {
-          auto dest = getIndexedHeapType();
-          auto src = getIndexedHeapType();
+          auto dest = getIndexedHeapType(pos);
+          auto src = getIndexedHeapType(pos);
           return builder.makeArrayCopy(dest, src);
         }
         case BinaryConsts::ArrayFill:
-          return builder.makeArrayFill(getIndexedHeapType());
+          return builder.makeArrayFill(getIndexedHeapType(pos));
         case BinaryConsts::ArrayInitData: {
-          auto type = getIndexedHeapType();
-          auto data = getDataName(getU32LEB());
+          auto type = getIndexedHeapType(pos);
+          auto data = getDataName(pos, getU32LEB(pos));
           return builder.makeArrayInitData(type, data);
         }
         case BinaryConsts::ArrayInitElem: {
-          auto type = getIndexedHeapType();
-          auto elem = getElemName(getU32LEB());
+          auto type = getIndexedHeapType(pos);
+          auto elem = getElemName(pos, getU32LEB(pos));
           return builder.makeArrayInitElem(type, elem);
         }
         case BinaryConsts::StringNewLossyUTF8Array:
@@ -4203,7 +4198,7 @@
           // the IR.
           return Ok{};
         case BinaryConsts::StringConst:
-          return builder.makeStringConst(getIndexedString());
+          return builder.makeStringConst(getIndexedString(pos));
         case BinaryConsts::StringMeasureUTF8:
           return builder.makeStringMeasure(StringMeasureUTF8);
         case BinaryConsts::StringMeasureWTF16:
@@ -4233,85 +4228,85 @@
   return Err{"unknown operation"};
 }
 
-void WasmBinaryReader::readExports() {
-  size_t num = getU32LEB();
+void WasmBinaryReader::readExports(size_t& pos) {
+  size_t num = getU32LEB(pos);
   std::unordered_set<Name> names;
   for (size_t i = 0; i < num; i++) {
     auto curr = std::make_unique<Export>();
-    curr->name = getInlineString();
+    curr->name = getInlineString(pos);
     if (!names.emplace(curr->name).second) {
-      throwError("duplicate export name");
+      throwError(pos, "duplicate export name");
     }
-    curr->kind = (ExternalKind)getU32LEB();
+    curr->kind = (ExternalKind)getU32LEB(pos);
     auto* ex = wasm.addExport(std::move(curr));
-    auto index = getU32LEB();
+    auto index = getU32LEB(pos);
     switch (ex->kind) {
       case ExternalKind::Function:
-        ex->value = getFunctionName(index);
+        ex->value = getFunctionName(pos, index);
         continue;
       case ExternalKind::Table:
-        ex->value = getTableName(index);
+        ex->value = getTableName(pos, index);
         continue;
       case ExternalKind::Memory:
-        ex->value = getMemoryName(index);
+        ex->value = getMemoryName(pos, index);
         continue;
       case ExternalKind::Global:
-        ex->value = getGlobalName(index);
+        ex->value = getGlobalName(pos, index);
         continue;
       case ExternalKind::Tag:
-        ex->value = getTagName(index);
+        ex->value = getTagName(pos, index);
         continue;
       case ExternalKind::Invalid:
         break;
     }
-    throwError("invalid export kind");
+    throwError(pos, "invalid export kind");
   }
 }
 
-Expression* WasmBinaryReader::readExpression() {
+Expression* WasmBinaryReader::readExpression(size_t& pos) {
   assert(builder.empty());
   while (input[pos] != BinaryConsts::End) {
-    auto inst = readInst();
+    auto inst = readInst(pos);
     if (auto* err = inst.getErr()) {
-      throwError(err->msg);
+      throwError(pos, err->msg);
     }
   }
   ++pos;
   auto expr = builder.build();
   if (auto* err = expr.getErr()) {
-    throwError(err->msg);
+    throwError(pos, err->msg);
   }
   return *expr;
 }
 
-void WasmBinaryReader::readStrings() {
-  auto reserved = getU32LEB();
+void WasmBinaryReader::readStrings(size_t& pos) {
+  auto reserved = getU32LEB(pos);
   if (reserved != 0) {
-    throwError("unexpected reserved value in strings");
+    throwError(pos, "unexpected reserved value in strings");
   }
-  size_t num = getU32LEB();
+  size_t num = getU32LEB(pos);
   for (size_t i = 0; i < num; i++) {
-    auto string = getInlineString(false);
+    auto string = getInlineString(pos, false);
     // Re-encode from WTF-8 to WTF-16.
     std::stringstream wtf16;
     if (!String::convertWTF8ToWTF16(wtf16, string.str)) {
-      throwError("invalid string constant");
+      throwError(pos, "invalid string constant");
     }
     // TODO: Use wtf16.view() once we have C++20.
     strings.push_back(wtf16.str());
   }
 }
 
-Name WasmBinaryReader::getIndexedString() {
-  auto index = getU32LEB();
+Name WasmBinaryReader::getIndexedString(size_t& pos) {
+  auto index = getU32LEB(pos);
   if (index >= strings.size()) {
-    throwError("bad string index");
+    throwError(pos, "bad string index");
   }
   return strings[index];
 }
 
-void WasmBinaryReader::readGlobals() {
-  size_t num = getU32LEB();
+void WasmBinaryReader::readGlobals(size_t& pos) {
+  size_t num = getU32LEB(pos);
   auto numImports = wasm.globals.size();
   std::unordered_set<Name> usedNames;
   for (auto& [index, name] : globalNames) {
@@ -4324,12 +4319,12 @@
   for (size_t i = 0; i < num; i++) {
     auto [name, isExplicit] = getOrMakeName(
       globalNames, numImports + i, makeName("global$", i), usedNames);
-    auto type = getConcreteType();
-    auto mutable_ = getU32LEB();
+    auto type = getConcreteType(pos);
+    auto mutable_ = getU32LEB(pos);
     if (mutable_ & ~1) {
-      throwError("Global mutability must be 0 or 1");
+      throwError(pos, "Global mutability must be 0 or 1");
     }
-    auto* init = readExpression();
+    auto* init = readExpression(pos);
     auto global = Builder::makeGlobal(
       name, type, init, mutable_ ? Builder::Mutable : Builder::Immutable);
     global->hasExplicitName = isExplicit;
@@ -4337,13 +4332,13 @@
   }
 }
 
-void WasmBinaryReader::validateBinary() {
+void WasmBinaryReader::validateBinary(size_t& pos) {
   if (hasDataCount && wasm.dataSegments.size() != dataCount) {
-    throwError("Number of segments does not agree with DataCount section");
+    throwError(pos, "Number of segments does not agree with DataCount section");
   }
 
   if (functionTypes.size() != numFuncImports + numFuncBodies) {
-    throwError("function and code sections have inconsistent lengths");
+    throwError(pos, "function and code sections have inconsistent lengths");
   }
 }
 
@@ -4365,19 +4360,19 @@
   }
 }
 
-void WasmBinaryReader::readDataSegmentCount() {
+void WasmBinaryReader::readDataSegmentCount(size_t& pos) {
   hasDataCount = true;
-  dataCount = getU32LEB();
+  dataCount = getU32LEB(pos);
   // Eagerly create the data segments so they are available during parsing of
   // the code section.
   createDataSegments(dataCount);
 }
 
-void WasmBinaryReader::readDataSegments() {
-  auto num = getU32LEB();
+void WasmBinaryReader::readDataSegments(size_t& pos) {
+  auto num = getU32LEB(pos);
   if (hasDataCount) {
     if (num != dataCount) {
-      throwError("data count and data sections disagree on size");
+      throwError(pos, "data count and data sections disagree on size");
     }
   } else {
     // We haven't already created the data segments, so create them now.
@@ -4386,10 +4381,11 @@
   assert(wasm.dataSegments.size() == num);
   for (size_t i = 0; i < num; i++) {
     auto& curr = wasm.dataSegments[i];
-    uint32_t flags = getU32LEB();
+    uint32_t flags = getU32LEB(pos);
     if (flags > 2) {
-      throwError("bad segment flags, must be 0, 1, or 2, not " +
-                 std::to_string(flags));
+      throwError(pos,
+                 "bad segment flags, must be 0, 1, or 2, not " +
+                   std::to_string(flags));
     }
     curr->isPassive = flags & BinaryConsts::IsPassive;
     if (curr->isPassive) {
@@ -4398,19 +4394,19 @@
     } else {
       Index memIdx = 0;
       if (flags & BinaryConsts::HasIndex) {
-        memIdx = getU32LEB();
+        memIdx = getU32LEB(pos);
       }
-      curr->memory = getMemoryName(memIdx);
-      curr->offset = readExpression();
+      curr->memory = getMemoryName(pos, memIdx);
+      curr->offset = readExpression(pos);
     }
-    auto size = getU32LEB();
-    auto data = getByteView(size);
+    auto size = getU32LEB(pos);
+    auto data = getByteView(pos, size);
     curr->data = {data.begin(), data.end()};
   }
 }
 
-void WasmBinaryReader::readTableDeclarations() {
-  auto num = getU32LEB();
+void WasmBinaryReader::readTableDeclarations(size_t& pos) {
+  auto num = getU32LEB(pos);
   auto numImports = wasm.tables.size();
   std::unordered_set<Name> usedNames;
   for (auto& [index, name] : tableNames) {
@@ -4423,29 +4419,30 @@
   for (size_t i = 0; i < num; i++) {
     auto [name, isExplicit] =
       getOrMakeName(tableNames, numImports + i, makeName("", i), usedNames);
-    auto elemType = getType();
+    auto elemType = getType(pos);
     if (!elemType.isRef()) {
-      throwError("Table type must be a reference type");
+      throwError(pos, "Table type must be a reference type");
     }
     auto table = Builder::makeTable(name, elemType);
     table->hasExplicitName = isExplicit;
     bool is_shared;
-    getResizableLimits(table->initial,
+    getResizableLimits(pos,
+                       table->initial,
                        table->max,
                        is_shared,
                        table->addressType,
                        Table::kUnlimitedSize);
     if (is_shared) {
-      throwError("Tables may not be shared");
+      throwError(pos, "Tables may not be shared");
     }
     wasm.addTable(std::move(table));
   }
 }
 
-void WasmBinaryReader::readElementSegments() {
-  auto num = getU32LEB();
+void WasmBinaryReader::readElementSegments(size_t& pos) {
+  auto num = getU32LEB(pos);
   if (num >= Table::kMaxSize) {
-    throwError("Too many segments");
+    throwError(pos, "Too many segments");
   }
   std::unordered_set<Name> usedNames;
   for (auto& [index, name] : elemNames) {
@@ -4458,7 +4455,7 @@
   for (size_t i = 0; i < num; i++) {
     auto [name, isExplicit] =
       getOrMakeName(elemNames, i, makeName("", i), usedNames);
-    auto flags = getU32LEB();
+    auto flags = getU32LEB(pos);
     bool isPassive = (flags & BinaryConsts::IsPassive) != 0;
     bool hasTableIdx = !isPassive && ((flags & BinaryConsts::HasIndex) != 0);
     bool isDeclarative =
@@ -4468,13 +4465,13 @@
     if (isDeclarative) {
       // Declared segments are needed in wasm text and binary, but not in
       // Binaryen IR; skip over the segment
-      [[maybe_unused]] auto type = getU32LEB();
-      auto num = getU32LEB();
+      [[maybe_unused]] auto type = getU32LEB(pos);
+      auto num = getU32LEB(pos);
       for (Index i = 0; i < num; i++) {
         if (usesExpressions) {
-          readExpression();
+          readExpression(pos);
         } else {
-          getU32LEB();
+          getU32LEB(pos);
         }
       }
       continue;
@@ -4486,39 +4483,41 @@
     if (!isPassive) {
       Index tableIdx = 0;
       if (hasTableIdx) {
-        tableIdx = getU32LEB();
+        tableIdx = getU32LEB(pos);
       }
 
       if (tableIdx >= wasm.tables.size()) {
-        throwError("Table index out of range.");
+        throwError(pos, "Table index out of range.");
       }
       auto* table = wasm.tables[tableIdx].get();
       segment->table = table->name;
-      segment->offset = readExpression();
+      segment->offset = readExpression(pos);
     }
 
     if (isPassive || hasTableIdx) {
       if (usesExpressions) {
-        segment->type = getType();
+        segment->type = getType(pos);
       } else {
-        auto elemKind = getU32LEB();
+        auto elemKind = getU32LEB(pos);
         if (elemKind != 0x0) {
-          throwError("Invalid kind (!= funcref(0)) since !usesExpressions.");
+          throwError(pos,
+                     "Invalid kind (!= funcref(0)) since !usesExpressions.");
         }
       }
     }
 
     auto& segmentData = segment->data;
-    auto size = getU32LEB();
+    auto size = getU32LEB(pos);
     if (usesExpressions) {
       for (Index j = 0; j < size; j++) {
-        segmentData.push_back(readExpression());
+        segmentData.push_back(readExpression(pos));
       }
     } else {
       for (Index j = 0; j < size; j++) {
-        Index index = getU32LEB();
-        auto sig = getTypeByFunctionIndex(index);
-        auto* refFunc = Builder(wasm).makeRefFunc(getFunctionName(index), sig);
+        Index index = getU32LEB(pos);
+        auto sig = getTypeByFunctionIndex(pos, index);
+        auto* refFunc =
+          Builder(wasm).makeRefFunc(getFunctionName(pos, index), sig);
         segmentData.push_back(refFunc);
       }
     }
@@ -4526,8 +4525,8 @@
   }
 }
 
-void WasmBinaryReader::readTags() {
-  size_t num = getU32LEB();
+void WasmBinaryReader::readTags(size_t& pos) {
+  size_t num = getU32LEB(pos);
   auto numImports = wasm.tags.size();
   std::unordered_set<Name> usedNames;
   for (auto& [index, name] : tagNames) {
@@ -4538,11 +4537,11 @@
     usedNames.insert(name);
   }
   for (size_t i = 0; i < num; i++) {
-    getInt8(); // Reserved 'attribute' field
+    getInt8(pos); // Reserved 'attribute' field
     auto [name, isExplicit] =
       getOrMakeName(tagNames, numImports + i, makeName("tag$", i), usedNames);
-    auto typeIndex = getU32LEB();
-    auto tag = Builder::makeTag(name, getSignatureByTypeIndex(typeIndex));
+    auto typeIndex = getU32LEB(pos);
+    auto tag = Builder::makeTag(name, getSignatureByTypeIndex(pos, typeIndex));
     tag->hasExplicitName = isExplicit;
     wasm.addTag(std::move(tag));
   }
@@ -4612,17 +4611,17 @@
 
 void WasmBinaryReader::findAndReadNames() {
   // Find the names section. Skip the magic and version.
-  assert(pos == 0);
-  getInt32();
-  getInt32();
+  size_t pos = 0;
+  getInt32(pos);
+  getInt32(pos);
   Index payloadLen, sectionPos;
   bool found = false;
-  while (more()) {
-    uint8_t sectionCode = getInt8();
-    payloadLen = getU32LEB();
+  while (more(pos)) {
+    uint8_t sectionCode = getInt8(pos);
+    payloadLen = getU32LEB(pos);
     sectionPos = pos;
     if (sectionCode == BinaryConsts::Section::Custom) {
-      auto sectionName = getInlineString();
+      auto sectionName = getInlineString(pos);
       if (sectionName.equals(BinaryConsts::CustomSections::Name)) {
         found = true;
         break;
@@ -4639,117 +4638,117 @@
   // Read the names.
   uint32_t lastType = 0;
   while (pos < sectionPos + payloadLen) {
-    auto nameType = getU32LEB();
+    auto nameType = getU32LEB(pos);
     if (lastType && nameType <= lastType) {
       std::cerr << "warning: out-of-order name subsection: " << nameType
                 << std::endl;
     }
     lastType = nameType;
-    auto subsectionSize = getU32LEB();
+    auto subsectionSize = getU32LEB(pos);
     auto subsectionPos = pos;
     using Subsection = BinaryConsts::CustomSections::Subsection;
     if (nameType == Subsection::NameModule) {
-      wasm.name = getInlineString();
+      wasm.name = getInlineString(pos);
     } else if (nameType == Subsection::NameFunction) {
-      auto num = getU32LEB();
+      auto num = getU32LEB(pos);
       NameProcessor processor;
       for (size_t i = 0; i < num; i++) {
-        auto index = getU32LEB();
-        auto rawName = getInlineString();
+        auto index = getU32LEB(pos);
+        auto rawName = getInlineString(pos);
         auto name = processor.process(rawName);
         functionNames[index] = name;
       }
     } else if (nameType == Subsection::NameLocal) {
-      auto numFuncs = getU32LEB();
+      auto numFuncs = getU32LEB(pos);
       for (size_t i = 0; i < numFuncs; i++) {
-        auto funcIndex = getU32LEB();
-        auto numLocals = getU32LEB();
+        auto funcIndex = getU32LEB(pos);
+        auto numLocals = getU32LEB(pos);
         NameProcessor processor;
         for (size_t j = 0; j < numLocals; j++) {
-          auto localIndex = getU32LEB();
-          auto rawName = getInlineString();
+          auto localIndex = getU32LEB(pos);
+          auto rawName = getInlineString(pos);
           auto name = processor.process(rawName);
           localNames[funcIndex][localIndex] = name;
         }
       }
     } else if (nameType == Subsection::NameType) {
-      auto num = getU32LEB();
+      auto num = getU32LEB(pos);
       NameProcessor processor;
       for (size_t i = 0; i < num; i++) {
-        auto index = getU32LEB();
-        auto rawName = getInlineString();
+        auto index = getU32LEB(pos);
+        auto rawName = getInlineString(pos);
         auto name = processor.process(rawName);
         typeNames[index] = name;
       }
     } else if (nameType == Subsection::NameTable) {
-      auto num = getU32LEB();
+      auto num = getU32LEB(pos);
       NameProcessor processor;
       for (size_t i = 0; i < num; i++) {
-        auto index = getU32LEB();
-        auto rawName = getInlineString();
+        auto index = getU32LEB(pos);
+        auto rawName = getInlineString(pos);
         auto name = processor.process(rawName);
         tableNames[index] = name;
       }
     } else if (nameType == Subsection::NameElem) {
-      auto num = getU32LEB();
+      auto num = getU32LEB(pos);
       NameProcessor processor;
       for (size_t i = 0; i < num; i++) {
-        auto index = getU32LEB();
-        auto rawName = getInlineString();
+        auto index = getU32LEB(pos);
+        auto rawName = getInlineString(pos);
         auto name = processor.process(rawName);
         elemNames[index] = name;
       }
     } else if (nameType == Subsection::NameMemory) {
-      auto num = getU32LEB();
+      auto num = getU32LEB(pos);
       NameProcessor processor;
       for (size_t i = 0; i < num; i++) {
-        auto index = getU32LEB();
-        auto rawName = getInlineString();
+        auto index = getU32LEB(pos);
+        auto rawName = getInlineString(pos);
         auto name = processor.process(rawName);
         memoryNames[index] = name;
       }
     } else if (nameType == Subsection::NameData) {
-      auto num = getU32LEB();
+      auto num = getU32LEB(pos);
       NameProcessor processor;
       for (size_t i = 0; i < num; i++) {
-        auto index = getU32LEB();
-        auto rawName = getInlineString();
+        auto index = getU32LEB(pos);
+        auto rawName = getInlineString(pos);
         auto name = processor.process(rawName);
         dataNames[index] = name;
       }
     } else if (nameType == Subsection::NameGlobal) {
-      auto num = getU32LEB();
+      auto num = getU32LEB(pos);
       NameProcessor processor;
       for (size_t i = 0; i < num; i++) {
-        auto index = getU32LEB();
-        auto rawName = getInlineString();
+        auto index = getU32LEB(pos);
+        auto rawName = getInlineString(pos);
         auto name = processor.process(rawName);
         globalNames[index] = name;
       }
     } else if (nameType == Subsection::NameField) {
-      auto numTypes = getU32LEB();
+      auto numTypes = getU32LEB(pos);
       for (size_t i = 0; i < numTypes; i++) {
-        auto typeIndex = getU32LEB();
+        auto typeIndex = getU32LEB(pos);
         bool validType =
           typeIndex < types.size() && types[typeIndex].isStruct();
         if (!validType) {
           std::cerr << "warning: invalid field index in name field section\n";
         }
-        auto numFields = getU32LEB();
+        auto numFields = getU32LEB(pos);
         NameProcessor processor;
         for (size_t i = 0; i < numFields; i++) {
-          auto fieldIndex = getU32LEB();
-          auto rawName = getInlineString();
+          auto fieldIndex = getU32LEB(pos);
+          auto rawName = getInlineString(pos);
           auto name = processor.process(rawName);
           fieldNames[typeIndex][fieldIndex] = name;
         }
       }
     } else if (nameType == Subsection::NameTag) {
-      auto num = getU32LEB();
+      auto num = getU32LEB(pos);
       NameProcessor processor;
       for (size_t i = 0; i < num; i++) {
-        auto index = getU32LEB();
-        auto rawName = getInlineString();
+        auto index = getU32LEB(pos);
+        auto rawName = getInlineString(pos);
         auto name = processor.process(rawName);
         tagNames[index] = name;
       }
@@ -4759,35 +4758,32 @@
       pos = subsectionPos + subsectionSize;
     }
     if (pos != subsectionPos + subsectionSize) {
-      throwError("bad names subsection position change");
+      throwError(pos, "bad names subsection position change");
     }
   }
   if (pos != sectionPos + payloadLen) {
-    throwError("bad names section position change");
+    throwError(pos, "bad names section position change");
   }
-
-  // Reset the position; we were just reading ahead.
-  pos = 0;
 }
 
-void WasmBinaryReader::readFeatures(size_t payloadLen) {
+void WasmBinaryReader::readFeatures(size_t& pos, size_t payloadLen) {
   wasm.hasFeaturesSection = true;
 
   auto sectionPos = pos;
-  size_t numFeatures = getU32LEB();
+  size_t numFeatures = getU32LEB(pos);
   for (size_t i = 0; i < numFeatures; ++i) {
-    uint8_t prefix = getInt8();
+    uint8_t prefix = getInt8(pos);
 
     bool disallowed = prefix == BinaryConsts::FeatureDisallowed;
     bool used = prefix == BinaryConsts::FeatureUsed;
 
     if (!disallowed && !used) {
-      throwError("Unrecognized feature policy prefix");
+      throwError(pos, "Unrecognized feature policy prefix");
     }
 
-    Name name = getInlineString();
+    Name name = getInlineString(pos);
     if (pos > sectionPos + payloadLen) {
-      throwError("ill-formed string extends beyond section");
+      throwError(pos, "ill-formed string extends beyond section");
     }
 
     FeatureSet feature;
@@ -4845,74 +4841,76 @@
     }
   }
   if (pos != sectionPos + payloadLen) {
-    throwError("bad features section size");
+    throwError(pos, "bad features section size");
   }
 }
 
-void WasmBinaryReader::readDylink(size_t payloadLen) {
+void WasmBinaryReader::readDylink(size_t& pos, size_t payloadLen) {
   wasm.dylinkSection = std::make_unique<DylinkSection>();
 
   auto sectionPos = pos;
 
   wasm.dylinkSection->isLegacy = true;
-  wasm.dylinkSection->memorySize = getU32LEB();
-  wasm.dylinkSection->memoryAlignment = getU32LEB();
-  wasm.dylinkSection->tableSize = getU32LEB();
-  wasm.dylinkSection->tableAlignment = getU32LEB();
+  wasm.dylinkSection->memorySize = getU32LEB(pos);
+  wasm.dylinkSection->memoryAlignment = getU32LEB(pos);
+  wasm.dylinkSection->tableSize = getU32LEB(pos);
+  wasm.dylinkSection->tableAlignment = getU32LEB(pos);
 
-  size_t numNeededDynlibs = getU32LEB();
+  size_t numNeededDynlibs = getU32LEB(pos);
   for (size_t i = 0; i < numNeededDynlibs; ++i) {
-    wasm.dylinkSection->neededDynlibs.push_back(getInlineString());
+    wasm.dylinkSection->neededDynlibs.push_back(getInlineString(pos));
   }
 
   if (pos != sectionPos + payloadLen) {
-    throwError("bad dylink section size");
+    throwError(pos, "bad dylink section size");
   }
 }
 
-void WasmBinaryReader::readDylink0(size_t payloadLen) {
+void WasmBinaryReader::readDylink0(size_t& pos, size_t payloadLen) {
   auto sectionPos = pos;
   uint32_t lastType = 0;
 
   wasm.dylinkSection = std::make_unique<DylinkSection>();
   while (pos < sectionPos + payloadLen) {
     auto oldPos = pos;
-    auto dylinkType = getU32LEB();
+    auto dylinkType = getU32LEB(pos);
     if (lastType && dylinkType <= lastType) {
       std::cerr << "warning: out-of-order dylink.0 subsection: " << dylinkType
                 << std::endl;
     }
     lastType = dylinkType;
-    auto subsectionSize = getU32LEB();
+    auto subsectionSize = getU32LEB(pos);
     auto subsectionPos = pos;
     if (dylinkType == BinaryConsts::CustomSections::Subsection::DylinkMemInfo) {
-      wasm.dylinkSection->memorySize = getU32LEB();
-      wasm.dylinkSection->memoryAlignment = getU32LEB();
-      wasm.dylinkSection->tableSize = getU32LEB();
-      wasm.dylinkSection->tableAlignment = getU32LEB();
+      wasm.dylinkSection->memorySize = getU32LEB(pos);
+      wasm.dylinkSection->memoryAlignment = getU32LEB(pos);
+      wasm.dylinkSection->tableSize = getU32LEB(pos);
+      wasm.dylinkSection->tableAlignment = getU32LEB(pos);
     } else if (dylinkType ==
                BinaryConsts::CustomSections::Subsection::DylinkNeeded) {
-      size_t numNeededDynlibs = getU32LEB();
+      size_t numNeededDynlibs = getU32LEB(pos);
       for (size_t i = 0; i < numNeededDynlibs; ++i) {
-        wasm.dylinkSection->neededDynlibs.push_back(getInlineString());
+        wasm.dylinkSection->neededDynlibs.push_back(getInlineString(pos));
       }
     } else {
       // Unknown subsection.  Stop parsing now and store the rest of
       // the section verbatim.
       pos = oldPos;
       size_t remaining = (sectionPos + payloadLen) - pos;
-      auto tail = getByteView(remaining);
+      auto tail = getByteView(pos, remaining);
       wasm.dylinkSection->tail = {tail.begin(), tail.end()};
       break;
     }
     if (pos != subsectionPos + subsectionSize) {
-      throwError("bad dylink.0 subsection position change");
+      throwError(pos, "bad dylink.0 subsection position change");
     }
   }
 }
 
-Index WasmBinaryReader::readMemoryAccess(Address& alignment, Address& offset) {
-  auto rawAlignment = getU32LEB();
+Index WasmBinaryReader::readMemoryAccess(size_t& pos,
+                                         Address& alignment,
+                                         Address& offset) {
+  auto rawAlignment = getU32LEB(pos);
   bool hasMemIdx = false;
   Index memIdx = 0;
   // Check bit 6 in the alignment to know whether a memory index is present per:
@@ -4924,27 +4922,28 @@
   }
 
   if (rawAlignment > 8) {
-    throwError("Alignment must be of a reasonable size");
+    throwError(pos, "Alignment must be of a reasonable size");
   }
 
   alignment = Bits::pow2(rawAlignment);
   if (hasMemIdx) {
-    memIdx = getU32LEB();
+    memIdx = getU32LEB(pos);
   }
   if (memIdx >= wasm.memories.size()) {
-    throwError("Memory index out of range while reading memory alignment.");
+    throwError(pos,
+               "Memory index out of range while reading memory alignment.");
   }
   auto* memory = wasm.memories[memIdx].get();
-  offset = memory->addressType == Type::i32 ? getU32LEB() : getU64LEB();
+  offset = memory->addressType == Type::i32 ? getU32LEB(pos) : getU64LEB(pos);
 
   return memIdx;
 }
 
 // TODO: make this the only version
-std::tuple<Name, Address, Address> WasmBinaryReader::getMemarg() {
+std::tuple<Name, Address, Address> WasmBinaryReader::getMemarg(size_t& pos) {
   Address alignment, offset;
-  auto memIdx = readMemoryAccess(alignment, offset);
-  return {getMemoryName(memIdx), alignment, offset};
+  auto memIdx = readMemoryAccess(pos, alignment, offset);
+  return {getMemoryName(pos, memIdx), alignment, offset};
 }
 
 } // namespace wasm