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 {
toString(ValType type)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 
toString(const WasmSignature & sig)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 
toString(const WasmGlobalType & type)58 std::string toString(const WasmGlobalType &type) {
59   return (type.Mutable ? "var " : "const ") +
60          toString(static_cast<ValType>(type.Type));
61 }
62 
toString(const WasmEventType & type)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 {
debugWrite(uint64_t offset,const Twine & msg)70 void debugWrite(uint64_t offset, const Twine &msg) {
71   LLVM_DEBUG(dbgs() << format("  | %08lld: ", offset) << msg << "\n");
72 }
73 
writeUleb128(raw_ostream & os,uint64_t number,const Twine & msg)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 
writeSleb128(raw_ostream & os,int64_t number,const Twine & msg)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 
writeBytes(raw_ostream & os,const char * bytes,size_t count,const Twine & msg)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 
writeStr(raw_ostream & os,StringRef string,const Twine & msg)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 
writeU8(raw_ostream & os,uint8_t byte,const Twine & msg)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 
writeU32(raw_ostream & os,uint32_t number,const Twine & msg)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 
writeU64(raw_ostream & os,uint64_t number,const Twine & msg)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 
writeValueType(raw_ostream & os,ValType type,const Twine & msg)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 
writeSig(raw_ostream & os,const WasmSignature & sig)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 
writeI32Const(raw_ostream & os,int32_t number,const Twine & msg)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 
writeI64Const(raw_ostream & os,int64_t number,const Twine & msg)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 
writePtrConst(raw_ostream & os,int64_t number,bool is64,const Twine & msg)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 
writeMemArg(raw_ostream & os,uint32_t alignment,uint64_t offset)147 void writeMemArg(raw_ostream &os, uint32_t alignment, uint64_t offset) {
148   writeUleb128(os, alignment, "alignment");
149   writeUleb128(os, offset, "offset");
150 }
151 
writeInitExpr(raw_ostream & os,const WasmInitExpr & initExpr)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 
writeLimits(raw_ostream & os,const WasmLimits & limits)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 
writeGlobalType(raw_ostream & os,const WasmGlobalType & type)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 
writeGlobal(raw_ostream & os,const WasmGlobal & global)192 void writeGlobal(raw_ostream &os, const WasmGlobal &global) {
193   writeGlobalType(os, global.Type);
194   writeInitExpr(os, global.InitExpr);
195 }
196 
writeEventType(raw_ostream & os,const WasmEventType & type)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 
writeEvent(raw_ostream & os,const WasmEvent & event)202 void writeEvent(raw_ostream &os, const WasmEvent &event) {
203   writeEventType(os, event.Type);
204 }
205 
writeTableType(raw_ostream & os,const WasmTableType & type)206 void writeTableType(raw_ostream &os, const WasmTableType &type) {
207   writeU8(os, WASM_TYPE_FUNCREF, "table type");
208   writeLimits(os, type.Limits);
209 }
210 
writeImport(raw_ostream & os,const WasmImport & import)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 
writeExport(raw_ostream & os,const WasmExport & export_)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