• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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