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::writeI32Const(raw_ostream &os, int32_t number, const Twine &msg) { 77 writeU8(os, WASM_OPCODE_I32_CONST, "i32.const"); 78 writeSleb128(os, number, msg); 79 } 80 81 void wasm::writeI64Const(raw_ostream &os, int32_t number, const Twine &msg) { 82 writeU8(os, WASM_OPCODE_I64_CONST, "i64.const"); 83 writeSleb128(os, number, msg); 84 } 85 86 void wasm::writeMemArg(raw_ostream &os, uint32_t alignment, uint32_t offset) { 87 writeUleb128(os, alignment, "alignment"); 88 writeUleb128(os, offset, "offset"); 89 } 90 91 void wasm::writeInitExpr(raw_ostream &os, const WasmInitExpr &initExpr) { 92 writeU8(os, initExpr.Opcode, "opcode"); 93 switch (initExpr.Opcode) { 94 case WASM_OPCODE_I32_CONST: 95 writeSleb128(os, initExpr.Value.Int32, "literal (i32)"); 96 break; 97 case WASM_OPCODE_I64_CONST: 98 writeSleb128(os, initExpr.Value.Int64, "literal (i64)"); 99 break; 100 case WASM_OPCODE_GLOBAL_GET: 101 writeUleb128(os, initExpr.Value.Global, "literal (global index)"); 102 break; 103 default: 104 fatal("unknown opcode in init expr: " + Twine(initExpr.Opcode)); 105 } 106 writeU8(os, WASM_OPCODE_END, "opcode:end"); 107 } 108 109 void wasm::writeLimits(raw_ostream &os, const WasmLimits &limits) { 110 writeU8(os, limits.Flags, "limits flags"); 111 writeUleb128(os, limits.Initial, "limits initial"); 112 if (limits.Flags & WASM_LIMITS_FLAG_HAS_MAX) 113 writeUleb128(os, limits.Maximum, "limits max"); 114 } 115 116 void wasm::writeGlobalType(raw_ostream &os, const WasmGlobalType &type) { 117 // TODO: Update WasmGlobalType to use ValType and remove this cast. 118 writeValueType(os, ValType(type.Type), "global type"); 119 writeU8(os, type.Mutable, "global mutable"); 120 } 121 122 void wasm::writeGlobal(raw_ostream &os, const WasmGlobal &global) { 123 writeGlobalType(os, global.Type); 124 writeInitExpr(os, global.InitExpr); 125 } 126 127 void wasm::writeEventType(raw_ostream &os, const WasmEventType &type) { 128 writeUleb128(os, type.Attribute, "event attribute"); 129 writeUleb128(os, type.SigIndex, "sig index"); 130 } 131 132 void wasm::writeEvent(raw_ostream &os, const WasmEvent &event) { 133 writeEventType(os, event.Type); 134 } 135 136 void wasm::writeTableType(raw_ostream &os, const llvm::wasm::WasmTable &type) { 137 writeU8(os, WASM_TYPE_FUNCREF, "table type"); 138 writeLimits(os, type.Limits); 139 } 140 141 void wasm::writeImport(raw_ostream &os, const WasmImport &import) { 142 writeStr(os, import.Module, "import module name"); 143 writeStr(os, import.Field, "import field name"); 144 writeU8(os, import.Kind, "import kind"); 145 switch (import.Kind) { 146 case WASM_EXTERNAL_FUNCTION: 147 writeUleb128(os, import.SigIndex, "import sig index"); 148 break; 149 case WASM_EXTERNAL_GLOBAL: 150 writeGlobalType(os, import.Global); 151 break; 152 case WASM_EXTERNAL_EVENT: 153 writeEventType(os, import.Event); 154 break; 155 case WASM_EXTERNAL_MEMORY: 156 writeLimits(os, import.Memory); 157 break; 158 case WASM_EXTERNAL_TABLE: 159 writeTableType(os, import.Table); 160 break; 161 default: 162 fatal("unsupported import type: " + Twine(import.Kind)); 163 } 164 } 165 166 void wasm::writeExport(raw_ostream &os, const WasmExport &export_) { 167 writeStr(os, export_.Name, "export name"); 168 writeU8(os, export_.Kind, "export kind"); 169 switch (export_.Kind) { 170 case WASM_EXTERNAL_FUNCTION: 171 writeUleb128(os, export_.Index, "function index"); 172 break; 173 case WASM_EXTERNAL_GLOBAL: 174 writeUleb128(os, export_.Index, "global index"); 175 break; 176 case WASM_EXTERNAL_MEMORY: 177 writeUleb128(os, export_.Index, "memory index"); 178 break; 179 case WASM_EXTERNAL_TABLE: 180 writeUleb128(os, export_.Index, "table index"); 181 break; 182 default: 183 fatal("unsupported export type: " + Twine(export_.Kind)); 184 } 185 } 186 } // namespace lld 187 188 std::string lld::toString(ValType type) { 189 switch (type) { 190 case ValType::I32: 191 return "i32"; 192 case ValType::I64: 193 return "i64"; 194 case ValType::F32: 195 return "f32"; 196 case ValType::F64: 197 return "f64"; 198 case ValType::V128: 199 return "v128"; 200 case ValType::EXNREF: 201 return "exnref"; 202 } 203 llvm_unreachable("Invalid wasm::ValType"); 204 } 205 206 std::string lld::toString(const WasmSignature &sig) { 207 SmallString<128> s("("); 208 for (ValType type : sig.Params) { 209 if (s.size() != 1) 210 s += ", "; 211 s += toString(type); 212 } 213 s += ") -> "; 214 if (sig.Returns.empty()) 215 s += "void"; 216 else 217 s += toString(sig.Returns[0]); 218 return s.str(); 219 } 220 221 std::string lld::toString(const WasmGlobalType &type) { 222 return (type.Mutable ? "var " : "const ") + 223 toString(static_cast<ValType>(type.Type)); 224 } 225 226 std::string lld::toString(const WasmEventType &type) { 227 if (type.Attribute == WASM_EVENT_ATTRIBUTE_EXCEPTION) 228 return "exception"; 229 return "unknown"; 230 } 231