[llvm] r304634 - [WebAssembly] Refactor WasmObjectWriter::writeObject

Sam Clegg via llvm-commits llvm-commits at lists.llvm.org
Fri Jun 2 19:01:24 PDT 2017


Author: sbc
Date: Fri Jun  2 21:01:24 2017
New Revision: 304634

URL: http://llvm.org/viewvc/llvm-project?rev=304634&view=rev
Log:
[WebAssembly] Refactor WasmObjectWriter::writeObject

The size of this function was getting a little out of.
control.  Split code for writing each section type into
seperate functions.

Differential Revision: https://reviews.llvm.org/D33792

Modified:
    llvm/trunk/lib/MC/WasmObjectWriter.cpp

Modified: llvm/trunk/lib/MC/WasmObjectWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/MC/WasmObjectWriter.cpp?rev=304634&r1=304633&r2=304634&view=diff
==============================================================================
--- llvm/trunk/lib/MC/WasmObjectWriter.cpp (original)
+++ llvm/trunk/lib/MC/WasmObjectWriter.cpp Fri Jun  2 21:01:24 2017
@@ -40,6 +40,7 @@ using namespace llvm;
 #define DEBUG_TYPE "reloc-info"
 
 namespace {
+
 // For patching purposes, we need to remember where each section starts, both
 // for patching up the section size field, and for patching up references to
 // locations within the section.
@@ -50,6 +51,82 @@ struct SectionBookkeeping {
   uint64_t ContentsOffset;
 };
 
+// The signature of a wasm function, in a struct capable of being used as a
+// DenseMap key.
+struct WasmFunctionType {
+  // Support empty and tombstone instances, needed by DenseMap.
+  enum { Plain, Empty, Tombstone } State;
+
+  // The return types of the function.
+  SmallVector<wasm::ValType, 1> Returns;
+
+  // The parameter types of the function.
+  SmallVector<wasm::ValType, 4> Params;
+
+  WasmFunctionType() : State(Plain) {}
+
+  bool operator==(const WasmFunctionType &Other) const {
+    return State == Other.State && Returns == Other.Returns &&
+           Params == Other.Params;
+  }
+};
+
+// Traits for using WasmFunctionType in a DenseMap.
+struct WasmFunctionTypeDenseMapInfo {
+  static WasmFunctionType getEmptyKey() {
+    WasmFunctionType FuncTy;
+    FuncTy.State = WasmFunctionType::Empty;
+    return FuncTy;
+  }
+  static WasmFunctionType getTombstoneKey() {
+    WasmFunctionType FuncTy;
+    FuncTy.State = WasmFunctionType::Tombstone;
+    return FuncTy;
+  }
+  static unsigned getHashValue(const WasmFunctionType &FuncTy) {
+    uintptr_t Value = FuncTy.State;
+    for (wasm::ValType Ret : FuncTy.Returns)
+      Value += DenseMapInfo<int32_t>::getHashValue(int32_t(Ret));
+    for (wasm::ValType Param : FuncTy.Params)
+      Value += DenseMapInfo<int32_t>::getHashValue(int32_t(Param));
+    return Value;
+  }
+  static bool isEqual(const WasmFunctionType &LHS,
+                      const WasmFunctionType &RHS) {
+    return LHS == RHS;
+  }
+};
+
+// A wasm import to be written into the import section.
+struct WasmImport {
+  StringRef ModuleName;
+  StringRef FieldName;
+  unsigned Kind;
+  int32_t Type;
+};
+
+// A wasm function to be written into the function section.
+struct WasmFunction {
+  int32_t Type;
+  const MCSymbolWasm *Sym;
+};
+
+// A wasm export to be written into the export section.
+struct WasmExport {
+  StringRef FieldName;
+  unsigned Kind;
+  uint32_t Index;
+};
+
+// A wasm global to be written into the global section.
+struct WasmGlobal {
+  wasm::ValType Type;
+  bool IsMutable;
+  bool HasImport;
+  uint64_t InitialValue;
+  uint32_t ImportIndex;
+};
+
 class WasmObjectWriter : public MCObjectWriter {
   /// Helper struct for containing some precomputed information on symbols.
   struct WasmSymbolData {
@@ -91,18 +168,10 @@ public:
       : MCObjectWriter(OS, /*IsLittleEndian=*/true), TargetObjectWriter(MOTW) {}
 
 private:
-  void reset() override {
-    MCObjectWriter::reset();
-  }
-
   ~WasmObjectWriter() override;
 
   void writeHeader(const MCAssembler &Asm);
 
-  void writeValueType(wasm::ValType Ty) {
-    encodeSLEB128(int32_t(Ty), getStream());
-  }
-
   void recordRelocation(MCAssembler &Asm, const MCAsmLayout &Layout,
                         const MCFragment *Fragment, const MCFixup &Fixup,
                         MCValue Target, bool &IsPCRel,
@@ -112,7 +181,37 @@ private:
                                 const MCAsmLayout &Layout) override;
 
   void writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) override;
+
+  void writeValueType(wasm::ValType Ty) {
+    encodeSLEB128(int32_t(Ty), getStream());
+  }
+
+  void writeTypeSection(const SmallVector<WasmFunctionType, 4> &FunctionTypes);
+  void writeImportSection(const SmallVector<WasmImport, 4> &Imports);
+  void writeFunctionSection(const SmallVector<WasmFunction, 4> &Functions);
+  void writeTableSection(const SmallVector<uint32_t, 4> &TableElems);
+  void writeMemorySection(const SmallVector<char, 0> &DataBytes);
+  void writeGlobalSection(const SmallVector<WasmGlobal, 4> &Globals);
+  void writeExportSection(const SmallVector<WasmExport, 4> &Exports);
+  void writeElemSection(const SmallVector<uint32_t, 4> &TableElems);
+  void writeCodeSection(const MCAssembler &Asm, const MCAsmLayout &Layout,
+                        DenseMap<const MCSymbolWasm *, uint32_t> &SymbolIndices,
+                        const SmallVector<WasmFunction, 4> &Functions);
+  uint64_t
+  writeDataSection(const SmallVector<char, 0> &DataBytes,
+                   DenseMap<const MCSymbolWasm *, uint32_t> &SymbolIndices);
+  void writeNameSection(const SmallVector<WasmFunction, 4> &Functions,
+                        const SmallVector<WasmImport, 4> &Imports,
+                        uint32_t NumFuncImports);
+  void writeCodeRelocSection(
+      DenseMap<const MCSymbolWasm *, uint32_t> &SymbolIndices);
+  void writeDataRelocSection(
+      DenseMap<const MCSymbolWasm *, uint32_t> &SymbolIndices,
+      uint64_t DataSectionHeaderSize);
+  void writeLinkingMetaDataSection(bool HasStackPointer,
+                                   uint32_t StackPointerGlobal);
 };
+
 } // end anonymous namespace
 
 WasmObjectWriter::~WasmObjectWriter() {}
@@ -278,86 +377,6 @@ void WasmObjectWriter::recordRelocation(
     DataRelocations.push_back(Rec);
 }
 
-namespace {
-
-// The signature of a wasm function, in a struct capable of being used as a
-// DenseMap key.
-struct WasmFunctionType {
-  // Support empty and tombstone instances, needed by DenseMap.
-  enum { Plain, Empty, Tombstone } State;
-
-  // The return types of the function.
-  SmallVector<wasm::ValType, 1> Returns;
-
-  // The parameter types of the function.
-  SmallVector<wasm::ValType, 4> Params;
-
-  WasmFunctionType() : State(Plain) {}
-
-  bool operator==(const WasmFunctionType &Other) const {
-    return State == Other.State && Returns == Other.Returns &&
-           Params == Other.Params;
-  }
-};
-
-// Traits for using WasmFunctionType in a DenseMap.
-struct WasmFunctionTypeDenseMapInfo {
-  static WasmFunctionType getEmptyKey() {
-    WasmFunctionType FuncTy;
-    FuncTy.State = WasmFunctionType::Empty;
-    return FuncTy;
-  }
-  static WasmFunctionType getTombstoneKey() {
-    WasmFunctionType FuncTy;
-    FuncTy.State = WasmFunctionType::Tombstone;
-    return FuncTy;
-  }
-  static unsigned getHashValue(const WasmFunctionType &FuncTy) {
-    uintptr_t Value = FuncTy.State;
-    for (wasm::ValType Ret : FuncTy.Returns)
-      Value += DenseMapInfo<int32_t>::getHashValue(int32_t(Ret));
-    for (wasm::ValType Param : FuncTy.Params)
-      Value += DenseMapInfo<int32_t>::getHashValue(int32_t(Param));
-    return Value;
-  }
-  static bool isEqual(const WasmFunctionType &LHS,
-                      const WasmFunctionType &RHS) {
-    return LHS == RHS;
-  }
-};
-
-// A wasm import to be written into the import section.
-struct WasmImport {
-  StringRef ModuleName;
-  StringRef FieldName;
-  unsigned Kind;
-  int32_t Type;
-};
-
-// A wasm function to be written into the function section.
-struct WasmFunction {
-  int32_t Type;
-  const MCSymbolWasm *Sym;
-};
-
-// A wasm export to be written into the export section.
-struct WasmExport {
-  StringRef FieldName;
-  unsigned Kind;
-  uint32_t Index;
-};
-
-// A wasm global to be written into the global section.
-struct WasmGlobal {
-  wasm::ValType Type;
-  bool IsMutable;
-  bool HasImport;
-  uint64_t InitialValue;
-  uint32_t ImportIndex;
-};
-
-} // end anonymous namespace
-
 // Write X as an (unsigned) LEB value at offset Offset in Stream, padded
 // to allow patching.
 static void
@@ -529,6 +548,367 @@ static void WriteTypeRelocations(
   }
 }
 
+void WasmObjectWriter::writeTypeSection(
+    const SmallVector<WasmFunctionType, 4> &FunctionTypes) {
+  if (FunctionTypes.empty())
+    return;
+
+  SectionBookkeeping Section;
+  startSection(Section, wasm::WASM_SEC_TYPE);
+
+  encodeULEB128(FunctionTypes.size(), getStream());
+
+  for (const WasmFunctionType &FuncTy : FunctionTypes) {
+    encodeSLEB128(wasm::WASM_TYPE_FUNC, getStream());
+    encodeULEB128(FuncTy.Params.size(), getStream());
+    for (wasm::ValType Ty : FuncTy.Params)
+      writeValueType(Ty);
+    encodeULEB128(FuncTy.Returns.size(), getStream());
+    for (wasm::ValType Ty : FuncTy.Returns)
+      writeValueType(Ty);
+  }
+
+  endSection(Section);
+}
+
+void WasmObjectWriter::writeImportSection(
+    const SmallVector<WasmImport, 4> &Imports) {
+  if (Imports.empty())
+    return;
+
+  SectionBookkeeping Section;
+  startSection(Section, wasm::WASM_SEC_IMPORT);
+
+  encodeULEB128(Imports.size(), getStream());
+  for (const WasmImport &Import : Imports) {
+    StringRef ModuleName = Import.ModuleName;
+    encodeULEB128(ModuleName.size(), getStream());
+    writeBytes(ModuleName);
+
+    StringRef FieldName = Import.FieldName;
+    encodeULEB128(FieldName.size(), getStream());
+    writeBytes(FieldName);
+
+    encodeULEB128(Import.Kind, getStream());
+
+    switch (Import.Kind) {
+    case wasm::WASM_EXTERNAL_FUNCTION:
+      encodeULEB128(Import.Type, getStream());
+      break;
+    case wasm::WASM_EXTERNAL_GLOBAL:
+      encodeSLEB128(int32_t(Import.Type), getStream());
+      encodeULEB128(0, getStream()); // mutability
+      break;
+    default:
+      llvm_unreachable("unsupported import kind");
+    }
+  }
+
+  endSection(Section);
+}
+
+void WasmObjectWriter::writeFunctionSection(
+    const SmallVector<WasmFunction, 4> &Functions) {
+  if (Functions.empty())
+    return;
+
+  SectionBookkeeping Section;
+  startSection(Section, wasm::WASM_SEC_FUNCTION);
+
+  encodeULEB128(Functions.size(), getStream());
+  for (const WasmFunction &Func : Functions)
+    encodeULEB128(Func.Type, getStream());
+
+  endSection(Section);
+}
+
+void WasmObjectWriter::writeTableSection(
+    const SmallVector<uint32_t, 4> &TableElems) {
+  // For now, always emit the table section, since indirect calls are not
+  // valid without it. In the future, we could perhaps be more clever and omit
+  // it if there are no indirect calls.
+  SectionBookkeeping Section;
+  startSection(Section, wasm::WASM_SEC_TABLE);
+
+  // The number of tables, fixed to 1 for now.
+  encodeULEB128(1, getStream());
+
+  encodeSLEB128(wasm::WASM_TYPE_ANYFUNC, getStream());
+
+  encodeULEB128(0, getStream());                 // flags
+  encodeULEB128(TableElems.size(), getStream()); // initial
+
+  endSection(Section);
+}
+
+void WasmObjectWriter::writeMemorySection(
+    const SmallVector<char, 0> &DataBytes) {
+  // For now, always emit the memory section, since loads and stores are not
+  // valid without it. In the future, we could perhaps be more clever and omit
+  // it if there are no loads or stores.
+  SectionBookkeeping Section;
+  uint32_t NumPages =
+      (DataBytes.size() + wasm::WasmPageSize - 1) / wasm::WasmPageSize;
+
+  startSection(Section, wasm::WASM_SEC_MEMORY);
+  encodeULEB128(1, getStream()); // number of memory spaces
+
+  encodeULEB128(0, getStream()); // flags
+  encodeULEB128(NumPages, getStream()); // initial
+
+  endSection(Section);
+}
+
+void WasmObjectWriter::writeGlobalSection(
+    const SmallVector<WasmGlobal, 4> &Globals) {
+  if (Globals.empty())
+    return;
+
+  SectionBookkeeping Section;
+  startSection(Section, wasm::WASM_SEC_GLOBAL);
+
+  encodeULEB128(Globals.size(), getStream());
+  for (const WasmGlobal &Global : Globals) {
+    writeValueType(Global.Type);
+    write8(Global.IsMutable);
+
+    if (Global.HasImport) {
+      assert(Global.InitialValue == 0);
+      write8(wasm::WASM_OPCODE_GET_GLOBAL);
+      encodeULEB128(Global.ImportIndex, getStream());
+    } else {
+      assert(Global.ImportIndex == 0);
+      write8(wasm::WASM_OPCODE_I32_CONST);
+      encodeSLEB128(Global.InitialValue, getStream()); // offset
+    }
+    write8(wasm::WASM_OPCODE_END);
+  }
+
+  endSection(Section);
+}
+
+void WasmObjectWriter::writeExportSection(
+    const SmallVector<WasmExport, 4> &Exports) {
+  if (Exports.empty())
+    return;
+
+  SectionBookkeeping Section;
+  startSection(Section, wasm::WASM_SEC_EXPORT);
+
+  encodeULEB128(Exports.size(), getStream());
+  for (const WasmExport &Export : Exports) {
+    encodeULEB128(Export.FieldName.size(), getStream());
+    writeBytes(Export.FieldName);
+
+    encodeSLEB128(Export.Kind, getStream());
+
+    encodeULEB128(Export.Index, getStream());
+  }
+
+  endSection(Section);
+}
+
+void WasmObjectWriter::writeElemSection(
+    const SmallVector<uint32_t, 4> &TableElems) {
+  if (TableElems.empty())
+    return;
+
+  SectionBookkeeping Section;
+  startSection(Section, wasm::WASM_SEC_ELEM);
+
+  encodeULEB128(1, getStream()); // number of "segments"
+  encodeULEB128(0, getStream()); // the table index
+
+  // init expr for starting offset
+  write8(wasm::WASM_OPCODE_I32_CONST);
+  encodeSLEB128(0, getStream());
+  write8(wasm::WASM_OPCODE_END);
+
+  encodeULEB128(TableElems.size(), getStream());
+  for (uint32_t Elem : TableElems)
+    encodeULEB128(Elem, getStream());
+
+  endSection(Section);
+}
+
+void WasmObjectWriter::writeCodeSection(
+    const MCAssembler &Asm, const MCAsmLayout &Layout,
+    DenseMap<const MCSymbolWasm *, uint32_t> &SymbolIndices,
+    const SmallVector<WasmFunction, 4> &Functions) {
+  if (Functions.empty())
+    return;
+
+  SectionBookkeeping Section;
+  startSection(Section, wasm::WASM_SEC_CODE);
+
+  encodeULEB128(Functions.size(), getStream());
+
+  for (const WasmFunction &Func : Functions) {
+    MCSectionWasm &FuncSection =
+        static_cast<MCSectionWasm &>(Func.Sym->getSection());
+
+    if (Func.Sym->isVariable())
+      report_fatal_error("weak symbols not supported yet");
+
+    if (Func.Sym->getOffset() != 0)
+      report_fatal_error("function sections must contain one function each");
+
+    if (!Func.Sym->getSize())
+      report_fatal_error("function symbols must have a size set with .size");
+
+    int64_t Size = 0;
+    if (!Func.Sym->getSize()->evaluateAsAbsolute(Size, Layout))
+      report_fatal_error(".size expression must be evaluatable");
+
+    encodeULEB128(Size, getStream());
+
+    FuncSection.setSectionOffset(getStream().tell() -
+                                 Section.ContentsOffset);
+
+    Asm.writeSectionData(&FuncSection, Layout);
+  }
+
+  // Apply the type index fixups for call_indirect etc. instructions.
+  for (size_t i = 0, e = TypeIndexFixups.size(); i < e; ++i) {
+    uint32_t Type = TypeIndexFixupTypes[i];
+    unsigned Padding = PaddingFor5ByteULEB128(Type);
+
+    const WasmRelocationEntry &Fixup = TypeIndexFixups[i];
+    assert(Fixup.Addend == 0);
+    assert(Fixup.Type == wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB);
+    uint64_t Offset = Fixup.Offset +
+                      Fixup.FixupSection->getSectionOffset();
+
+    uint8_t Buffer[16];
+    unsigned SizeLen = encodeULEB128(Type, Buffer, Padding);
+    assert(SizeLen == 5);
+    getStream().pwrite((char *)Buffer, SizeLen,
+                       Section.ContentsOffset + Offset);
+  }
+
+  // Apply fixups.
+  ApplyRelocations(CodeRelocations, getStream(), SymbolIndices,
+                   Section.ContentsOffset);
+
+  endSection(Section);
+}
+
+uint64_t WasmObjectWriter::writeDataSection(
+    const SmallVector<char, 0> &DataBytes,
+    DenseMap<const MCSymbolWasm *, uint32_t> &SymbolIndices) {
+  if (DataBytes.empty())
+    return 0;
+
+  SectionBookkeeping Section;
+  startSection(Section, wasm::WASM_SEC_DATA);
+
+  encodeULEB128(1, getStream()); // count
+  encodeULEB128(0, getStream()); // memory index
+  write8(wasm::WASM_OPCODE_I32_CONST);
+  encodeSLEB128(0, getStream()); // offset
+  write8(wasm::WASM_OPCODE_END);
+  encodeULEB128(DataBytes.size(), getStream()); // size
+  uint32_t HeaderSize = getStream().tell() - Section.ContentsOffset;
+  writeBytes(DataBytes); // data
+
+  // Apply fixups.
+  ApplyRelocations(DataRelocations, getStream(), SymbolIndices,
+                   Section.ContentsOffset + HeaderSize);
+
+  endSection(Section);
+  return HeaderSize;
+}
+
+void WasmObjectWriter::writeNameSection(
+    const SmallVector<WasmFunction, 4> &Functions,
+    const SmallVector<WasmImport, 4> &Imports,
+    unsigned NumFuncImports) {
+  uint32_t TotalFunctions = NumFuncImports + Functions.size();
+  if (TotalFunctions == 0)
+    return;
+
+  SectionBookkeeping Section;
+  startSection(Section, wasm::WASM_SEC_CUSTOM, "name");
+  SectionBookkeeping SubSection;
+  startSection(SubSection, wasm::WASM_NAMES_FUNCTION);
+
+  encodeULEB128(TotalFunctions, getStream());
+  uint32_t Index = 0;
+  for (const WasmImport &Import : Imports) {
+    if (Import.Kind == wasm::WASM_EXTERNAL_FUNCTION) {
+      encodeULEB128(Index, getStream());
+      encodeULEB128(Import.FieldName.size(), getStream());
+      writeBytes(Import.FieldName);
+      ++Index;
+    }
+  }
+  for (const WasmFunction &Func : Functions) {
+    encodeULEB128(Index, getStream());
+    encodeULEB128(Func.Sym->getName().size(), getStream());
+    writeBytes(Func.Sym->getName());
+    ++Index;
+  }
+
+  endSection(SubSection);
+  endSection(Section);
+}
+
+void WasmObjectWriter::writeCodeRelocSection(
+    DenseMap<const MCSymbolWasm *, uint32_t> &SymbolIndices) {
+  // See: https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md
+  // for descriptions of the reloc sections.
+
+  if (CodeRelocations.empty())
+    return;
+
+  SectionBookkeeping Section;
+  startSection(Section, wasm::WASM_SEC_CUSTOM, "reloc.CODE");
+
+  encodeULEB128(wasm::WASM_SEC_CODE, getStream());
+  encodeULEB128(CodeRelocations.size() + TypeIndexFixups.size(), getStream());
+
+  WriteRelocations(CodeRelocations, getStream(), SymbolIndices, 0);
+  WriteTypeRelocations(TypeIndexFixups, TypeIndexFixupTypes, getStream());
+
+  endSection(Section);
+}
+
+void WasmObjectWriter::writeDataRelocSection(
+    DenseMap<const MCSymbolWasm *, uint32_t> &SymbolIndices,
+    uint64_t DataSectionHeaderSize) {
+  // See: https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md
+  // for descriptions of the reloc sections.
+
+  if (DataRelocations.empty())
+    return;
+
+  SectionBookkeeping Section;
+  startSection(Section, wasm::WASM_SEC_CUSTOM, "reloc.DATA");
+
+  encodeULEB128(wasm::WASM_SEC_DATA, getStream());
+  encodeULEB128(DataRelocations.size(), getStream());
+
+  WriteRelocations(DataRelocations, getStream(), SymbolIndices,
+                   DataSectionHeaderSize);
+
+  endSection(Section);
+}
+
+void WasmObjectWriter::writeLinkingMetaDataSection(
+    bool HasStackPointer, uint32_t StackPointerGlobal) {
+  if (!HasStackPointer)
+    return;
+  SectionBookkeeping Section;
+  startSection(Section, wasm::WASM_SEC_CUSTOM, "linking");
+
+  encodeULEB128(1, getStream()); // count
+
+  encodeULEB128(wasm::WASM_STACK_POINTER, getStream()); // type
+  encodeULEB128(StackPointerGlobal, getStream()); // id
+
+  endSection(Section);
+}
+
 void WasmObjectWriter::writeObject(MCAssembler &Asm,
                                    const MCAsmLayout &Layout) {
   MCContext &Ctx = Asm.getContext();
@@ -832,322 +1212,23 @@ void WasmObjectWriter::writeObject(MCAss
   // Write out the Wasm header.
   writeHeader(Asm);
 
-  SectionBookkeeping Section;
-
-  // === Type Section =========================================================
-  if (!FunctionTypes.empty()) {
-    startSection(Section, wasm::WASM_SEC_TYPE);
-
-    encodeULEB128(FunctionTypes.size(), getStream());
-
-    for (WasmFunctionType &FuncTy : FunctionTypes) {
-      encodeSLEB128(wasm::WASM_TYPE_FUNC, getStream());
-      encodeULEB128(FuncTy.Params.size(), getStream());
-      for (wasm::ValType Ty : FuncTy.Params)
-        writeValueType(Ty);
-      encodeULEB128(FuncTy.Returns.size(), getStream());
-      for (wasm::ValType Ty : FuncTy.Returns)
-        writeValueType(Ty);
-    }
-
-    endSection(Section);
-  }
-
-  // === Import Section ========================================================
-  if (!Imports.empty()) {
-    startSection(Section, wasm::WASM_SEC_IMPORT);
-
-    encodeULEB128(Imports.size(), getStream());
-    for (const WasmImport &Import : Imports) {
-      StringRef ModuleName = Import.ModuleName;
-      encodeULEB128(ModuleName.size(), getStream());
-      writeBytes(ModuleName);
-
-      StringRef FieldName = Import.FieldName;
-      encodeULEB128(FieldName.size(), getStream());
-      writeBytes(FieldName);
-
-      encodeULEB128(Import.Kind, getStream());
-
-      switch (Import.Kind) {
-      case wasm::WASM_EXTERNAL_FUNCTION:
-        encodeULEB128(Import.Type, getStream());
-        break;
-      case wasm::WASM_EXTERNAL_GLOBAL:
-        encodeSLEB128(int32_t(Import.Type), getStream());
-        encodeULEB128(0, getStream()); // mutability
-        break;
-      default:
-        llvm_unreachable("unsupported import kind");
-      }
-    }
-
-    endSection(Section);
-  }
-
-  // === Function Section ======================================================
-  if (!Functions.empty()) {
-    startSection(Section, wasm::WASM_SEC_FUNCTION);
-
-    encodeULEB128(Functions.size(), getStream());
-    for (const WasmFunction &Func : Functions)
-      encodeULEB128(Func.Type, getStream());
-
-    endSection(Section);
-  }
-
-  // === Table Section =========================================================
-  // For now, always emit the table section, since indirect calls are not
-  // valid without it. In the future, we could perhaps be more clever and omit
-  // it if there are no indirect calls.
-  startSection(Section, wasm::WASM_SEC_TABLE);
-
-  // The number of tables, fixed to 1 for now.
-  encodeULEB128(1, getStream());
-
-  encodeSLEB128(wasm::WASM_TYPE_ANYFUNC, getStream());
-
-  encodeULEB128(0, getStream());                 // flags
-  encodeULEB128(TableElems.size(), getStream()); // initial
-
-  endSection(Section);
-
-  // === Memory Section ========================================================
-  // For now, always emit the memory section, since loads and stores are not
-  // valid without it. In the future, we could perhaps be more clever and omit
-  // it if there are no loads or stores.
-  uint32_t NumPages =
-      (DataBytes.size() + wasm::WasmPageSize - 1) / wasm::WasmPageSize;
-
-  startSection(Section, wasm::WASM_SEC_MEMORY);
-  encodeULEB128(1, getStream()); // number of memory spaces
-
-  encodeULEB128(0, getStream()); // flags
-  encodeULEB128(NumPages, getStream()); // initial
-
-  endSection(Section);
-
-  // === Global Section ========================================================
-  if (!Globals.empty()) {
-    startSection(Section, wasm::WASM_SEC_GLOBAL);
-
-    encodeULEB128(Globals.size(), getStream());
-    for (const WasmGlobal &Global : Globals) {
-      writeValueType(Global.Type);
-      write8(Global.IsMutable);
-
-      if (Global.HasImport) {
-        assert(Global.InitialValue == 0);
-        write8(wasm::WASM_OPCODE_GET_GLOBAL);
-        encodeULEB128(Global.ImportIndex, getStream());
-      } else {
-        assert(Global.ImportIndex == 0);
-        write8(wasm::WASM_OPCODE_I32_CONST);
-        encodeSLEB128(Global.InitialValue, getStream()); // offset
-      }
-      write8(wasm::WASM_OPCODE_END);
-    }
-
-    endSection(Section);
-  }
-
-  // === Export Section ========================================================
-  if (!Exports.empty()) {
-    startSection(Section, wasm::WASM_SEC_EXPORT);
-
-    encodeULEB128(Exports.size(), getStream());
-    for (const WasmExport &Export : Exports) {
-      encodeULEB128(Export.FieldName.size(), getStream());
-      writeBytes(Export.FieldName);
-
-      encodeSLEB128(Export.Kind, getStream());
-
-      encodeULEB128(Export.Index, getStream());
-    }
-
-    endSection(Section);
-  }
-
-#if 0 // TODO: Start Section
-  if (HaveStartFunction) {
-    // === Start Section =========================================================
-    startSection(Section, wasm::WASM_SEC_START);
-
-    encodeSLEB128(StartFunction, getStream());
-
-    endSection(Section);
-  }
-#endif
-
-  // === Elem Section ==========================================================
-  if (!TableElems.empty()) {
-    startSection(Section, wasm::WASM_SEC_ELEM);
-
-    encodeULEB128(1, getStream()); // number of "segments"
-    encodeULEB128(0, getStream()); // the table index
-
-    // init expr for starting offset
-    write8(wasm::WASM_OPCODE_I32_CONST);
-    encodeSLEB128(0, getStream());
-    write8(wasm::WASM_OPCODE_END);
-
-    encodeULEB128(TableElems.size(), getStream());
-    for (uint32_t Elem : TableElems)
-      encodeULEB128(Elem, getStream());
-
-    endSection(Section);
-  }
-
-  // === Code Section ==========================================================
-  if (!Functions.empty()) {
-    startSection(Section, wasm::WASM_SEC_CODE);
-
-    encodeULEB128(Functions.size(), getStream());
-
-    for (const WasmFunction &Func : Functions) {
-      MCSectionWasm &FuncSection =
-          static_cast<MCSectionWasm &>(Func.Sym->getSection());
-
-      if (Func.Sym->isVariable())
-        report_fatal_error("weak symbols not supported yet");
-
-      if (Func.Sym->getOffset() != 0)
-        report_fatal_error("function sections must contain one function each");
-
-      if (!Func.Sym->getSize())
-        report_fatal_error("function symbols must have a size set with .size");
-
-      int64_t Size = 0;
-      if (!Func.Sym->getSize()->evaluateAsAbsolute(Size, Layout))
-        report_fatal_error(".size expression must be evaluatable");
-
-      encodeULEB128(Size, getStream());
-
-      FuncSection.setSectionOffset(getStream().tell() -
-                                   Section.ContentsOffset);
-
-      Asm.writeSectionData(&FuncSection, Layout);
-    }
-
-    // Apply the type index fixups for call_indirect etc. instructions.
-    for (size_t i = 0, e = TypeIndexFixups.size(); i < e; ++i) {
-      uint32_t Type = TypeIndexFixupTypes[i];
-      unsigned Padding = PaddingFor5ByteULEB128(Type);
-
-      const WasmRelocationEntry &Fixup = TypeIndexFixups[i];
-      assert(Fixup.Addend == 0);
-      assert(Fixup.Type == wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB);
-      uint64_t Offset = Fixup.Offset +
-                        Fixup.FixupSection->getSectionOffset();
-
-      uint8_t Buffer[16];
-      unsigned SizeLen = encodeULEB128(Type, Buffer, Padding);
-      assert(SizeLen == 5);
-      getStream().pwrite((char *)Buffer, SizeLen,
-                         Section.ContentsOffset + Offset);
-    }
-
-    // Apply fixups.
-    ApplyRelocations(CodeRelocations, getStream(), SymbolIndices,
-                     Section.ContentsOffset);
-
-    endSection(Section);
-  }
-
-  // === Data Section ==========================================================
-  uint32_t DataSectionHeaderSize = 0;
-  if (!DataBytes.empty()) {
-    startSection(Section, wasm::WASM_SEC_DATA);
-
-    encodeULEB128(1, getStream()); // count
-    encodeULEB128(0, getStream()); // memory index
-    write8(wasm::WASM_OPCODE_I32_CONST);
-    encodeSLEB128(0, getStream()); // offset
-    write8(wasm::WASM_OPCODE_END);
-    encodeULEB128(DataBytes.size(), getStream()); // size
-    DataSectionHeaderSize = getStream().tell() - Section.ContentsOffset;
-    writeBytes(DataBytes); // data
-
-    // Apply fixups.
-    ApplyRelocations(DataRelocations, getStream(), SymbolIndices,
-                     Section.ContentsOffset + DataSectionHeaderSize);
-
-    endSection(Section);
-  }
-
-  // === Name Section ==========================================================
-  uint32_t TotalFunctions = NumFuncImports + Functions.size();
-  if (TotalFunctions != 0) {
-    startSection(Section, wasm::WASM_SEC_CUSTOM, "name");
-    SectionBookkeeping SubSection;
-    startSection(SubSection, wasm::WASM_NAMES_FUNCTION);
-
-    encodeULEB128(TotalFunctions, getStream());
-    uint32_t Index = 0;
-    for (const WasmImport &Import : Imports) {
-      if (Import.Kind == wasm::WASM_EXTERNAL_FUNCTION) {
-        encodeULEB128(Index, getStream());
-        encodeULEB128(Import.FieldName.size(), getStream());
-        writeBytes(Import.FieldName);
-        ++Index;
-      }
-    }
-    for (const WasmFunction &Func : Functions) {
-      encodeULEB128(Index, getStream());
-      encodeULEB128(Func.Sym->getName().size(), getStream());
-      writeBytes(Func.Sym->getName());
-      ++Index;
-    }
-
-    endSection(SubSection);
-    endSection(Section);
-  }
-
-  // See: https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md
-  // for descriptions of the reloc sections.
-
-  // === Code Reloc Section ====================================================
-  if (!CodeRelocations.empty()) {
-    startSection(Section, wasm::WASM_SEC_CUSTOM, "reloc.CODE");
-
-    encodeULEB128(wasm::WASM_SEC_CODE, getStream());
-
-    encodeULEB128(CodeRelocations.size() + TypeIndexFixups.size(), getStream());
-
-    WriteRelocations(CodeRelocations, getStream(), SymbolIndices, 0);
-    WriteTypeRelocations(TypeIndexFixups, TypeIndexFixupTypes, getStream());
-
-    endSection(Section);
-  }
-
-  // === Data Reloc Section ====================================================
-  if (!DataRelocations.empty()) {
-    startSection(Section, wasm::WASM_SEC_CUSTOM, "reloc.DATA");
-
-    encodeULEB128(wasm::WASM_SEC_DATA, getStream());
-
-    encodeULEB128(DataRelocations.size(), getStream());
-
-    WriteRelocations(DataRelocations, getStream(), SymbolIndices,
-                     DataSectionHeaderSize);
-
-    endSection(Section);
-  }
-
-  // === Linking Metadata Section ==============================================
-  if (HasStackPointer) {
-    startSection(Section, wasm::WASM_SEC_CUSTOM, "linking");
-
-    encodeULEB128(1, getStream()); // count
-
-    encodeULEB128(wasm::WASM_STACK_POINTER, getStream()); // type
-    encodeULEB128(StackPointerGlobal, getStream()); // id
-
-    endSection(Section);
-  }
+  writeTypeSection(FunctionTypes);
+  writeImportSection(Imports);
+  writeFunctionSection(Functions);
+  writeTableSection(TableElems);
+  writeMemorySection(DataBytes);
+  writeGlobalSection(Globals);
+  writeExportSection(Exports);
+  // TODO: Start Section
+  writeElemSection(TableElems);
+  writeCodeSection(Asm, Layout, SymbolIndices, Functions);
+  uint64_t DataSectionHeaderSize = writeDataSection(DataBytes, SymbolIndices);
+  writeNameSection(Functions, Imports, NumFuncImports);
+  writeCodeRelocSection(SymbolIndices);
+  writeDataRelocSection(SymbolIndices, DataSectionHeaderSize);
+  writeLinkingMetaDataSection(HasStackPointer, StackPointerGlobal);
 
   // TODO: Translate the .comment section to the output.
-
   // TODO: Translate debug sections to the output.
 }
 




More information about the llvm-commits mailing list