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