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