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