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