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