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 std::string toString(ValType type) { 22 switch (type) { 23 case ValType::I32: 24 return "i32"; 25 case ValType::I64: 26 return "i64"; 27 case ValType::F32: 28 return "f32"; 29 case ValType::F64: 30 return "f64"; 31 case ValType::V128: 32 return "v128"; 33 case ValType::FUNCREF: 34 return "funcref"; 35 case ValType::EXTERNREF: 36 return "externref"; 37 } 38 llvm_unreachable("Invalid wasm::ValType"); 39 } 40 41 std::string toString(const WasmSignature &sig) { 42 SmallString<128> s("("); 43 for (ValType type : sig.Params) { 44 if (s.size() != 1) 45 s += ", "; 46 s += toString(type); 47 } 48 s += ") -> "; 49 if (sig.Returns.empty()) 50 s += "void"; 51 else 52 s += toString(sig.Returns[0]); 53 return std::string(s.str()); 54 } 55 56 std::string toString(const WasmGlobalType &type) { 57 return (type.Mutable ? "var " : "const ") + 58 toString(static_cast<ValType>(type.Type)); 59 } 60 61 static std::string toString(const llvm::wasm::WasmLimits &limits) { 62 std::string ret; 63 ret += "flags=0x" + std::to_string(limits.Flags); 64 ret += "; min=" + std::to_string(limits.Minimum); 65 if (limits.Flags & WASM_LIMITS_FLAG_HAS_MAX) 66 ret += "; max=" + std::to_string(limits.Maximum); 67 return ret; 68 } 69 70 std::string toString(const WasmTableType &type) { 71 SmallString<128> ret(""); 72 return "type=" + toString(static_cast<ValType>(type.ElemType)) + 73 "; limits=[" + toString(type.Limits) + "]"; 74 } 75 76 namespace wasm { 77 #ifdef LLVM_DEBUG 78 void debugWrite(uint64_t offset, const Twine &msg) { 79 LLVM_DEBUG(dbgs() << format(" | %08lld: ", offset) << msg << "\n"); 80 } 81 #endif 82 83 void writeUleb128(raw_ostream &os, uint64_t number, const Twine &msg) { 84 debugWrite(os.tell(), msg + "[" + utohexstr(number) + "]"); 85 encodeULEB128(number, os); 86 } 87 88 void writeSleb128(raw_ostream &os, int64_t number, const Twine &msg) { 89 debugWrite(os.tell(), msg + "[" + utohexstr(number) + "]"); 90 encodeSLEB128(number, os); 91 } 92 93 void writeBytes(raw_ostream &os, const char *bytes, size_t count, 94 const Twine &msg) { 95 debugWrite(os.tell(), msg + " [data[" + Twine(count) + "]]"); 96 os.write(bytes, count); 97 } 98 99 void writeStr(raw_ostream &os, StringRef string, const Twine &msg) { 100 debugWrite(os.tell(), 101 msg + " [str[" + Twine(string.size()) + "]: " + string + "]"); 102 encodeULEB128(string.size(), os); 103 os.write(string.data(), string.size()); 104 } 105 106 void writeU8(raw_ostream &os, uint8_t byte, const Twine &msg) { 107 debugWrite(os.tell(), msg + " [0x" + utohexstr(byte) + "]"); 108 os << byte; 109 } 110 111 void writeU32(raw_ostream &os, uint32_t number, const Twine &msg) { 112 debugWrite(os.tell(), msg + "[0x" + utohexstr(number) + "]"); 113 support::endian::write(os, number, support::little); 114 } 115 116 void writeU64(raw_ostream &os, uint64_t number, const Twine &msg) { 117 debugWrite(os.tell(), msg + "[0x" + utohexstr(number) + "]"); 118 support::endian::write(os, number, support::little); 119 } 120 121 void writeValueType(raw_ostream &os, ValType type, const Twine &msg) { 122 writeU8(os, static_cast<uint8_t>(type), 123 msg + "[type: " + toString(type) + "]"); 124 } 125 126 void writeSig(raw_ostream &os, const WasmSignature &sig) { 127 writeU8(os, WASM_TYPE_FUNC, "signature type"); 128 writeUleb128(os, sig.Params.size(), "param Count"); 129 for (ValType paramType : sig.Params) { 130 writeValueType(os, paramType, "param type"); 131 } 132 writeUleb128(os, sig.Returns.size(), "result Count"); 133 for (ValType returnType : sig.Returns) { 134 writeValueType(os, returnType, "result type"); 135 } 136 } 137 138 void writeI32Const(raw_ostream &os, int32_t number, const Twine &msg) { 139 writeU8(os, WASM_OPCODE_I32_CONST, "i32.const"); 140 writeSleb128(os, number, msg); 141 } 142 143 void writeI64Const(raw_ostream &os, int64_t number, const Twine &msg) { 144 writeU8(os, WASM_OPCODE_I64_CONST, "i64.const"); 145 writeSleb128(os, number, msg); 146 } 147 148 void writePtrConst(raw_ostream &os, int64_t number, bool is64, 149 const Twine &msg) { 150 if (is64) 151 writeI64Const(os, number, msg); 152 else 153 writeI32Const(os, static_cast<int32_t>(number), msg); 154 } 155 156 void writeMemArg(raw_ostream &os, uint32_t alignment, uint64_t offset) { 157 writeUleb128(os, alignment, "alignment"); 158 writeUleb128(os, offset, "offset"); 159 } 160 161 void writeInitExpr(raw_ostream &os, const WasmInitExpr &initExpr) { 162 writeU8(os, initExpr.Opcode, "opcode"); 163 switch (initExpr.Opcode) { 164 case WASM_OPCODE_I32_CONST: 165 writeSleb128(os, initExpr.Value.Int32, "literal (i32)"); 166 break; 167 case WASM_OPCODE_I64_CONST: 168 writeSleb128(os, initExpr.Value.Int64, "literal (i64)"); 169 break; 170 case WASM_OPCODE_F32_CONST: 171 writeU32(os, initExpr.Value.Float32, "literal (f32)"); 172 break; 173 case WASM_OPCODE_F64_CONST: 174 writeU64(os, initExpr.Value.Float64, "literal (f64)"); 175 break; 176 case WASM_OPCODE_GLOBAL_GET: 177 writeUleb128(os, initExpr.Value.Global, "literal (global index)"); 178 break; 179 case WASM_OPCODE_REF_NULL: 180 writeValueType(os, ValType::EXTERNREF, "literal (externref type)"); 181 break; 182 default: 183 fatal("unknown opcode in init expr: " + Twine(initExpr.Opcode)); 184 } 185 writeU8(os, WASM_OPCODE_END, "opcode:end"); 186 } 187 188 void writeLimits(raw_ostream &os, const WasmLimits &limits) { 189 writeU8(os, limits.Flags, "limits flags"); 190 writeUleb128(os, limits.Minimum, "limits min"); 191 if (limits.Flags & WASM_LIMITS_FLAG_HAS_MAX) 192 writeUleb128(os, limits.Maximum, "limits max"); 193 } 194 195 void writeGlobalType(raw_ostream &os, const WasmGlobalType &type) { 196 // TODO: Update WasmGlobalType to use ValType and remove this cast. 197 writeValueType(os, ValType(type.Type), "global type"); 198 writeU8(os, type.Mutable, "global mutable"); 199 } 200 201 void writeTableType(raw_ostream &os, const WasmTableType &type) { 202 writeValueType(os, ValType(type.ElemType), "table type"); 203 writeLimits(os, type.Limits); 204 } 205 206 void writeImport(raw_ostream &os, const WasmImport &import) { 207 writeStr(os, import.Module, "import module name"); 208 writeStr(os, import.Field, "import field name"); 209 writeU8(os, import.Kind, "import kind"); 210 switch (import.Kind) { 211 case WASM_EXTERNAL_FUNCTION: 212 writeUleb128(os, import.SigIndex, "import sig index"); 213 break; 214 case WASM_EXTERNAL_GLOBAL: 215 writeGlobalType(os, import.Global); 216 break; 217 case WASM_EXTERNAL_TAG: 218 writeUleb128(os, 0, "tag attribute"); // Reserved "attribute" field 219 writeUleb128(os, import.SigIndex, "import sig index"); 220 break; 221 case WASM_EXTERNAL_MEMORY: 222 writeLimits(os, import.Memory); 223 break; 224 case WASM_EXTERNAL_TABLE: 225 writeTableType(os, import.Table); 226 break; 227 default: 228 fatal("unsupported import type: " + Twine(import.Kind)); 229 } 230 } 231 232 void writeExport(raw_ostream &os, const WasmExport &export_) { 233 writeStr(os, export_.Name, "export name"); 234 writeU8(os, export_.Kind, "export kind"); 235 switch (export_.Kind) { 236 case WASM_EXTERNAL_FUNCTION: 237 writeUleb128(os, export_.Index, "function index"); 238 break; 239 case WASM_EXTERNAL_GLOBAL: 240 writeUleb128(os, export_.Index, "global index"); 241 break; 242 case WASM_EXTERNAL_TAG: 243 writeUleb128(os, export_.Index, "tag index"); 244 break; 245 case WASM_EXTERNAL_MEMORY: 246 writeUleb128(os, export_.Index, "memory index"); 247 break; 248 case WASM_EXTERNAL_TABLE: 249 writeUleb128(os, export_.Index, "table index"); 250 break; 251 default: 252 fatal("unsupported export type: " + Twine(export_.Kind)); 253 } 254 } 255 256 } // namespace wasm 257 } // namespace lld 258