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(uint8_t Type) { 23 switch (Type) { 24 case WASM_TYPE_I32: 25 return "i32"; 26 case WASM_TYPE_I64: 27 return "i64"; 28 case WASM_TYPE_F32: 29 return "f32"; 30 case WASM_TYPE_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 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::Writer<support::little>(OS).write(Number); 74 } 75 76 void wasm::writeValueType(raw_ostream &OS, uint8_t Type, const Twine &Msg) { 77 writeU8(OS, Type, Msg + "[type: " + valueTypeToString(Type) + "]"); 78 } 79 80 void wasm::writeSig(raw_ostream &OS, const WasmSignature &Sig) { 81 writeU8(OS, WASM_TYPE_FUNC, "signature type"); 82 writeUleb128(OS, Sig.ParamTypes.size(), "param Count"); 83 for (uint8_t ParamType : Sig.ParamTypes) { 84 writeValueType(OS, ParamType, "param type"); 85 } 86 if (Sig.ReturnType == WASM_TYPE_NORESULT) { 87 writeUleb128(OS, 0, "result Count"); 88 } else { 89 writeUleb128(OS, 1, "result Count"); 90 writeValueType(OS, Sig.ReturnType, "result type"); 91 } 92 } 93 94 void wasm::writeInitExpr(raw_ostream &OS, const WasmInitExpr &InitExpr) { 95 writeU8(OS, InitExpr.Opcode, "opcode"); 96 switch (InitExpr.Opcode) { 97 case WASM_OPCODE_I32_CONST: 98 writeSleb128(OS, InitExpr.Value.Int32, "literal (i32)"); 99 break; 100 case WASM_OPCODE_I64_CONST: 101 writeSleb128(OS, InitExpr.Value.Int64, "literal (i64)"); 102 break; 103 case WASM_OPCODE_GET_GLOBAL: 104 writeUleb128(OS, InitExpr.Value.Global, "literal (global index)"); 105 break; 106 default: 107 fatal("unknown opcode in init expr: " + Twine(InitExpr.Opcode)); 108 } 109 writeU8(OS, WASM_OPCODE_END, "opcode:end"); 110 } 111 112 void wasm::writeLimits(raw_ostream &OS, const WasmLimits &Limits) { 113 writeU8(OS, Limits.Flags, "limits flags"); 114 writeUleb128(OS, Limits.Initial, "limits initial"); 115 if (Limits.Flags & WASM_LIMITS_FLAG_HAS_MAX) 116 writeUleb128(OS, Limits.Maximum, "limits max"); 117 } 118 119 void wasm::writeGlobalType(raw_ostream &OS, const WasmGlobalType &Type) { 120 writeValueType(OS, 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::EXCEPT_REF: 189 return "except_ref"; 190 } 191 llvm_unreachable("Invalid wasm::ValType"); 192 } 193 194 std::string lld::toString(const WasmSignature &Sig) { 195 SmallString<128> S("("); 196 for (uint32_t Type : Sig.ParamTypes) { 197 if (S.size() != 1) 198 S += ", "; 199 S += toString(static_cast<ValType>(Type)); 200 } 201 S += ") -> "; 202 if (Sig.ReturnType == WASM_TYPE_NORESULT) 203 S += "void"; 204 else 205 S += toString(static_cast<ValType>(Sig.ReturnType)); 206 return S.str(); 207 } 208 209 std::string lld::toString(const WasmGlobalType &Sig) { 210 return (Sig.Mutable ? "var " : "const ") + 211 toString(static_cast<ValType>(Sig.Type)); 212 } 213