1 //===- WriterUtils.cpp ----------------------------------------------------===// 2 // 3 // The LLVM Linker 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "WriterUtils.h" 11 #include "lld/Common/ErrorHandler.h" 12 #include "llvm/Support/Debug.h" 13 #include "llvm/Support/EndianStream.h" 14 #include "llvm/Support/LEB128.h" 15 16 #define DEBUG_TYPE "lld" 17 18 using namespace llvm; 19 using namespace llvm::wasm; 20 using namespace lld::wasm; 21 22 namespace lld { 23 24 void wasm::debugWrite(uint64_t Offset, const Twine &Msg) { 25 LLVM_DEBUG(dbgs() << format(" | %08lld: ", Offset) << Msg << "\n"); 26 } 27 28 void wasm::writeUleb128(raw_ostream &OS, uint32_t Number, const Twine &Msg) { 29 debugWrite(OS.tell(), Msg + "[" + utohexstr(Number) + "]"); 30 encodeULEB128(Number, OS); 31 } 32 33 void wasm::writeSleb128(raw_ostream &OS, int32_t Number, const Twine &Msg) { 34 debugWrite(OS.tell(), Msg + "[" + utohexstr(Number) + "]"); 35 encodeSLEB128(Number, OS); 36 } 37 38 void wasm::writeBytes(raw_ostream &OS, const char *Bytes, size_t Count, 39 const Twine &Msg) { 40 debugWrite(OS.tell(), Msg + " [data[" + Twine(Count) + "]]"); 41 OS.write(Bytes, Count); 42 } 43 44 void wasm::writeStr(raw_ostream &OS, StringRef String, const Twine &Msg) { 45 debugWrite(OS.tell(), 46 Msg + " [str[" + Twine(String.size()) + "]: " + String + "]"); 47 encodeULEB128(String.size(), OS); 48 OS.write(String.data(), String.size()); 49 } 50 51 void wasm::writeU8(raw_ostream &OS, uint8_t Byte, const Twine &Msg) { 52 debugWrite(OS.tell(), Msg + " [0x" + utohexstr(Byte) + "]"); 53 OS << Byte; 54 } 55 56 void wasm::writeU32(raw_ostream &OS, uint32_t Number, const Twine &Msg) { 57 debugWrite(OS.tell(), Msg + "[0x" + utohexstr(Number) + "]"); 58 support::endian::write(OS, Number, support::little); 59 } 60 61 void wasm::writeValueType(raw_ostream &OS, ValType Type, const Twine &Msg) { 62 writeU8(OS, static_cast<uint8_t>(Type), 63 Msg + "[type: " + toString(Type) + "]"); 64 } 65 66 void wasm::writeSig(raw_ostream &OS, const WasmSignature &Sig) { 67 writeU8(OS, WASM_TYPE_FUNC, "signature type"); 68 writeUleb128(OS, Sig.Params.size(), "param Count"); 69 for (ValType ParamType : Sig.Params) { 70 writeValueType(OS, ParamType, "param type"); 71 } 72 writeUleb128(OS, Sig.Returns.size(), "result Count"); 73 if (Sig.Returns.size()) { 74 writeValueType(OS, Sig.Returns[0], "result type"); 75 } 76 } 77 78 void wasm::writeInitExpr(raw_ostream &OS, const WasmInitExpr &InitExpr) { 79 writeU8(OS, InitExpr.Opcode, "opcode"); 80 switch (InitExpr.Opcode) { 81 case WASM_OPCODE_I32_CONST: 82 writeSleb128(OS, InitExpr.Value.Int32, "literal (i32)"); 83 break; 84 case WASM_OPCODE_I64_CONST: 85 writeSleb128(OS, InitExpr.Value.Int64, "literal (i64)"); 86 break; 87 case WASM_OPCODE_GET_GLOBAL: 88 writeUleb128(OS, InitExpr.Value.Global, "literal (global index)"); 89 break; 90 default: 91 fatal("unknown opcode in init expr: " + Twine(InitExpr.Opcode)); 92 } 93 writeU8(OS, WASM_OPCODE_END, "opcode:end"); 94 } 95 96 void wasm::writeLimits(raw_ostream &OS, const WasmLimits &Limits) { 97 writeU8(OS, Limits.Flags, "limits flags"); 98 writeUleb128(OS, Limits.Initial, "limits initial"); 99 if (Limits.Flags & WASM_LIMITS_FLAG_HAS_MAX) 100 writeUleb128(OS, Limits.Maximum, "limits max"); 101 } 102 103 void wasm::writeGlobalType(raw_ostream &OS, const WasmGlobalType &Type) { 104 // TODO: Update WasmGlobalType to use ValType and remove this cast. 105 writeValueType(OS, ValType(Type.Type), "global type"); 106 writeU8(OS, Type.Mutable, "global mutable"); 107 } 108 109 void wasm::writeGlobal(raw_ostream &OS, const WasmGlobal &Global) { 110 writeGlobalType(OS, Global.Type); 111 writeInitExpr(OS, Global.InitExpr); 112 } 113 114 void wasm::writeTableType(raw_ostream &OS, const llvm::wasm::WasmTable &Type) { 115 writeU8(OS, WASM_TYPE_ANYFUNC, "table type"); 116 writeLimits(OS, Type.Limits); 117 } 118 119 void wasm::writeImport(raw_ostream &OS, const WasmImport &Import) { 120 writeStr(OS, Import.Module, "import module name"); 121 writeStr(OS, Import.Field, "import field name"); 122 writeU8(OS, Import.Kind, "import kind"); 123 switch (Import.Kind) { 124 case WASM_EXTERNAL_FUNCTION: 125 writeUleb128(OS, Import.SigIndex, "import sig index"); 126 break; 127 case WASM_EXTERNAL_GLOBAL: 128 writeGlobalType(OS, Import.Global); 129 break; 130 case WASM_EXTERNAL_MEMORY: 131 writeLimits(OS, Import.Memory); 132 break; 133 case WASM_EXTERNAL_TABLE: 134 writeTableType(OS, Import.Table); 135 break; 136 default: 137 fatal("unsupported import type: " + Twine(Import.Kind)); 138 } 139 } 140 141 void wasm::writeExport(raw_ostream &OS, const WasmExport &Export) { 142 writeStr(OS, Export.Name, "export name"); 143 writeU8(OS, Export.Kind, "export kind"); 144 switch (Export.Kind) { 145 case WASM_EXTERNAL_FUNCTION: 146 writeUleb128(OS, Export.Index, "function index"); 147 break; 148 case WASM_EXTERNAL_GLOBAL: 149 writeUleb128(OS, Export.Index, "global index"); 150 break; 151 case WASM_EXTERNAL_MEMORY: 152 writeUleb128(OS, Export.Index, "memory index"); 153 break; 154 case WASM_EXTERNAL_TABLE: 155 writeUleb128(OS, Export.Index, "table index"); 156 break; 157 default: 158 fatal("unsupported export type: " + Twine(Export.Kind)); 159 } 160 } 161 } // namespace lld 162 163 std::string lld::toString(ValType Type) { 164 switch (Type) { 165 case ValType::I32: 166 return "i32"; 167 case ValType::I64: 168 return "i64"; 169 case ValType::F32: 170 return "f32"; 171 case ValType::F64: 172 return "f64"; 173 case ValType::V128: 174 return "v128"; 175 case ValType::EXCEPT_REF: 176 return "except_ref"; 177 } 178 llvm_unreachable("Invalid wasm::ValType"); 179 } 180 181 std::string lld::toString(const WasmSignature &Sig) { 182 SmallString<128> S("("); 183 for (ValType Type : Sig.Params) { 184 if (S.size() != 1) 185 S += ", "; 186 S += toString(Type); 187 } 188 S += ") -> "; 189 if (Sig.Returns.size() == 0) 190 S += "void"; 191 else 192 S += toString(Sig.Returns[0]); 193 return S.str(); 194 } 195 196 std::string lld::toString(const WasmGlobalType &Sig) { 197 return (Sig.Mutable ? "var " : "const ") + 198 toString(static_cast<ValType>(Sig.Type)); 199 } 200