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