1 // Copyright 2015 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/wasm/function-body-decoder.h"
6
7 #include "src/flags/flags.h"
8 #include "src/handles/handles.h"
9 #include "src/objects/objects-inl.h"
10 #include "src/utils/ostreams.h"
11 #include "src/wasm/decoder.h"
12 #include "src/wasm/function-body-decoder-impl.h"
13 #include "src/wasm/wasm-limits.h"
14 #include "src/wasm/wasm-linkage.h"
15 #include "src/wasm/wasm-module.h"
16 #include "src/wasm/wasm-opcodes-inl.h"
17
18 namespace v8 {
19 namespace internal {
20 namespace wasm {
21
DecodeLocalDecls(const WasmFeatures & enabled,BodyLocalDecls * decls,const byte * start,const byte * end)22 bool DecodeLocalDecls(const WasmFeatures& enabled, BodyLocalDecls* decls,
23 const byte* start, const byte* end) {
24 WasmFeatures no_features = WasmFeatures::None();
25 Zone* zone = decls->type_list.get_allocator().zone();
26 WasmDecoder<Decoder::kFullValidation> decoder(
27 zone, nullptr, enabled, &no_features, nullptr, start, end, 0);
28 uint32_t length;
29 if (!decoder.DecodeLocals(decoder.pc(), &length, 0)) {
30 decls->encoded_size = 0;
31 return false;
32 }
33 DCHECK(decoder.ok());
34 decls->encoded_size = length;
35 // Copy the decoded locals types into {decls->type_list}.
36 DCHECK(decls->type_list.empty());
37 decls->type_list = std::move(decoder.local_types_);
38 return true;
39 }
40
BytecodeIterator(const byte * start,const byte * end,BodyLocalDecls * decls)41 BytecodeIterator::BytecodeIterator(const byte* start, const byte* end,
42 BodyLocalDecls* decls)
43 : Decoder(start, end) {
44 if (decls != nullptr) {
45 if (DecodeLocalDecls(WasmFeatures::All(), decls, start, end)) {
46 pc_ += decls->encoded_size;
47 if (pc_ > end_) pc_ = end_;
48 }
49 }
50 }
51
VerifyWasmCode(AccountingAllocator * allocator,const WasmFeatures & enabled,const WasmModule * module,WasmFeatures * detected,const FunctionBody & body)52 DecodeResult VerifyWasmCode(AccountingAllocator* allocator,
53 const WasmFeatures& enabled,
54 const WasmModule* module, WasmFeatures* detected,
55 const FunctionBody& body) {
56 Zone zone(allocator, ZONE_NAME);
57 WasmFullDecoder<Decoder::kFullValidation, EmptyInterface> decoder(
58 &zone, module, enabled, detected, body);
59 decoder.Decode();
60 return decoder.toResult(nullptr);
61 }
62
OpcodeLength(const byte * pc,const byte * end)63 unsigned OpcodeLength(const byte* pc, const byte* end) {
64 WasmFeatures no_features = WasmFeatures::None();
65 Zone* no_zone = nullptr;
66 WasmModule* no_module = nullptr;
67 FunctionSig* no_sig = nullptr;
68 WasmDecoder<Decoder::kNoValidation> decoder(no_zone, no_module, no_features,
69 &no_features, no_sig, pc, end, 0);
70 return WasmDecoder<Decoder::kNoValidation>::OpcodeLength(&decoder, pc);
71 }
72
StackEffect(const WasmModule * module,const FunctionSig * sig,const byte * pc,const byte * end)73 std::pair<uint32_t, uint32_t> StackEffect(const WasmModule* module,
74 const FunctionSig* sig,
75 const byte* pc, const byte* end) {
76 WasmFeatures unused_detected_features = WasmFeatures::None();
77 Zone* no_zone = nullptr;
78 WasmDecoder<Decoder::kNoValidation> decoder(
79 no_zone, module, WasmFeatures::All(), &unused_detected_features, sig, pc,
80 end);
81 return decoder.StackEffect(pc);
82 }
83
PrintRawWasmCode(const byte * start,const byte * end)84 void PrintRawWasmCode(const byte* start, const byte* end) {
85 AccountingAllocator allocator;
86 PrintRawWasmCode(&allocator, FunctionBody{nullptr, 0, start, end}, nullptr,
87 kPrintLocals);
88 }
89
90 namespace {
RawOpcodeName(WasmOpcode opcode)91 const char* RawOpcodeName(WasmOpcode opcode) {
92 switch (opcode) {
93 #define DECLARE_NAME_CASE(name, opcode, sig) \
94 case kExpr##name: \
95 return "kExpr" #name;
96 FOREACH_OPCODE(DECLARE_NAME_CASE)
97 #undef DECLARE_NAME_CASE
98 default:
99 break;
100 }
101 return "Unknown";
102 }
PrefixName(WasmOpcode prefix_opcode)103 const char* PrefixName(WasmOpcode prefix_opcode) {
104 switch (prefix_opcode) {
105 #define DECLARE_PREFIX_CASE(name, opcode) \
106 case k##name##Prefix: \
107 return "k" #name "Prefix";
108 FOREACH_PREFIX(DECLARE_PREFIX_CASE)
109 #undef DECLARE_PREFIX_CASE
110 default:
111 return "Unknown prefix";
112 }
113 }
114 } // namespace
115
PrintRawWasmCode(AccountingAllocator * allocator,const FunctionBody & body,const WasmModule * module,PrintLocals print_locals)116 bool PrintRawWasmCode(AccountingAllocator* allocator, const FunctionBody& body,
117 const WasmModule* module, PrintLocals print_locals) {
118 StdoutStream os;
119 return PrintRawWasmCode(allocator, body, module, print_locals, os);
120 }
121
PrintRawWasmCode(AccountingAllocator * allocator,const FunctionBody & body,const WasmModule * module,PrintLocals print_locals,std::ostream & os,std::vector<int> * line_numbers)122 bool PrintRawWasmCode(AccountingAllocator* allocator, const FunctionBody& body,
123 const WasmModule* module, PrintLocals print_locals,
124 std::ostream& os, std::vector<int>* line_numbers) {
125 Zone zone(allocator, ZONE_NAME);
126 WasmFeatures unused_detected_features = WasmFeatures::None();
127 WasmDecoder<Decoder::kNoValidation> decoder(
128 &zone, module, WasmFeatures::All(), &unused_detected_features, body.sig,
129 body.start, body.end);
130 int line_nr = 0;
131 constexpr int kNoByteCode = -1;
132
133 // Print the function signature.
134 if (body.sig) {
135 os << "// signature: " << *body.sig << std::endl;
136 if (line_numbers) line_numbers->push_back(kNoByteCode);
137 ++line_nr;
138 }
139
140 // Print the local declarations.
141 BodyLocalDecls decls(&zone);
142 BytecodeIterator i(body.start, body.end, &decls);
143 if (body.start != i.pc() && print_locals == kPrintLocals) {
144 os << "// locals:";
145 if (!decls.type_list.empty()) {
146 ValueType type = decls.type_list[0];
147 uint32_t count = 0;
148 for (size_t pos = 0; pos < decls.type_list.size(); ++pos) {
149 if (decls.type_list[pos] == type) {
150 ++count;
151 } else {
152 os << " " << count << " " << type.name();
153 type = decls.type_list[pos];
154 count = 1;
155 }
156 }
157 os << " " << count << " " << type.name();
158 }
159 os << std::endl;
160 if (line_numbers) line_numbers->push_back(kNoByteCode);
161 ++line_nr;
162
163 for (const byte* locals = body.start; locals < i.pc(); locals++) {
164 os << (locals == body.start ? "0x" : " 0x") << AsHex(*locals, 2) << ",";
165 }
166 os << std::endl;
167 if (line_numbers) line_numbers->push_back(kNoByteCode);
168 ++line_nr;
169 }
170
171 os << "// body:" << std::endl;
172 if (line_numbers) line_numbers->push_back(kNoByteCode);
173 ++line_nr;
174 unsigned control_depth = 0;
175 for (; i.has_next(); i.next()) {
176 unsigned length =
177 WasmDecoder<Decoder::kNoValidation>::OpcodeLength(&decoder, i.pc());
178
179 unsigned offset = 1;
180 WasmOpcode opcode = i.current();
181 WasmOpcode prefix = kExprUnreachable;
182 bool has_prefix = WasmOpcodes::IsPrefixOpcode(opcode);
183 if (has_prefix) {
184 prefix = i.current();
185 opcode = i.prefixed_opcode();
186 offset = 2;
187 }
188 if (line_numbers) line_numbers->push_back(i.position());
189 if (opcode == kExprElse || opcode == kExprCatch) {
190 control_depth--;
191 }
192
193 int num_whitespaces = control_depth < 32 ? 2 * control_depth : 64;
194
195 // 64 whitespaces
196 const char* padding =
197 " ";
198 os.write(padding, num_whitespaces);
199
200 if (has_prefix) {
201 os << PrefixName(prefix) << ", ";
202 }
203
204 os << RawOpcodeName(opcode) << ",";
205
206 if (opcode == kExprLoop || opcode == kExprIf || opcode == kExprBlock ||
207 opcode == kExprTry) {
208 DCHECK_EQ(2, length);
209
210 // TODO(7748) Update this for gc and ref types if needed
211 switch (i.pc()[1]) {
212 #define CASE_LOCAL_TYPE(local_name, type_name) \
213 case k##local_name##Code: \
214 os << " kWasm" #type_name ","; \
215 break;
216
217 CASE_LOCAL_TYPE(I32, I32)
218 CASE_LOCAL_TYPE(I64, I64)
219 CASE_LOCAL_TYPE(F32, F32)
220 CASE_LOCAL_TYPE(F64, F64)
221 CASE_LOCAL_TYPE(S128, S128)
222 CASE_LOCAL_TYPE(Void, Stmt)
223 default:
224 os << " 0x" << AsHex(i.pc()[1], 2) << ",";
225 break;
226 }
227 #undef CASE_LOCAL_TYPE
228 } else {
229 for (unsigned j = offset; j < length; ++j) {
230 os << " 0x" << AsHex(i.pc()[j], 2) << ",";
231 }
232 }
233
234 os << " // " << WasmOpcodes::OpcodeName(opcode);
235
236 switch (opcode) {
237 case kExprElse:
238 case kExprCatch:
239 os << " @" << i.pc_offset();
240 control_depth++;
241 break;
242 case kExprLoop:
243 case kExprIf:
244 case kExprBlock:
245 case kExprTry: {
246 BlockTypeImmediate<Decoder::kNoValidation> imm(WasmFeatures::All(), &i,
247 i.pc() + 1);
248 os << " @" << i.pc_offset();
249 if (decoder.Complete(imm)) {
250 for (uint32_t i = 0; i < imm.out_arity(); i++) {
251 os << " " << imm.out_type(i).name();
252 }
253 }
254 control_depth++;
255 break;
256 }
257 case kExprEnd:
258 os << " @" << i.pc_offset();
259 control_depth--;
260 break;
261 case kExprBr: {
262 BranchDepthImmediate<Decoder::kNoValidation> imm(&i, i.pc() + 1);
263 os << " depth=" << imm.depth;
264 break;
265 }
266 case kExprBrIf: {
267 BranchDepthImmediate<Decoder::kNoValidation> imm(&i, i.pc() + 1);
268 os << " depth=" << imm.depth;
269 break;
270 }
271 case kExprBrTable: {
272 BranchTableImmediate<Decoder::kNoValidation> imm(&i, i.pc() + 1);
273 os << " entries=" << imm.table_count;
274 break;
275 }
276 case kExprCallIndirect: {
277 CallIndirectImmediate<Decoder::kNoValidation> imm(WasmFeatures::All(),
278 &i, i.pc() + 1);
279 os << " sig #" << imm.sig_index;
280 if (decoder.Complete(imm)) {
281 os << ": " << *imm.sig;
282 }
283 break;
284 }
285 case kExprCallFunction: {
286 CallFunctionImmediate<Decoder::kNoValidation> imm(&i, i.pc() + 1);
287 os << " function #" << imm.index;
288 if (decoder.Complete(imm)) {
289 os << ": " << *imm.sig;
290 }
291 break;
292 }
293 default:
294 break;
295 }
296 os << std::endl;
297 ++line_nr;
298 }
299 DCHECK(!line_numbers || line_numbers->size() == static_cast<size_t>(line_nr));
300
301 return decoder.ok();
302 }
303
AnalyzeLoopAssignmentForTesting(Zone * zone,size_t num_locals,const byte * start,const byte * end)304 BitVector* AnalyzeLoopAssignmentForTesting(Zone* zone, size_t num_locals,
305 const byte* start, const byte* end) {
306 WasmFeatures no_features = WasmFeatures::None();
307 WasmDecoder<Decoder::kFullValidation> decoder(
308 zone, nullptr, no_features, &no_features, nullptr, start, end, 0);
309 return WasmDecoder<Decoder::kFullValidation>::AnalyzeLoopAssignment(
310 &decoder, start, static_cast<uint32_t>(num_locals), zone);
311 }
312
313 } // namespace wasm
314 } // namespace internal
315 } // namespace v8
316