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