• 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/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