blob: b8a86c357badb86cda8244c2ecb9c4d878a3cafb [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001// 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
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005#include "src/signature.h"
6
Ben Murdoch097c5b22016-05-18 11:27:45 +01007#include "src/bit-vector.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008#include "src/flags.h"
9#include "src/handles.h"
10#include "src/zone-containers.h"
11
12#include "src/wasm/ast-decoder.h"
13#include "src/wasm/decoder.h"
14#include "src/wasm/wasm-module.h"
15#include "src/wasm/wasm-opcodes.h"
16
Ben Murdochda12d292016-06-02 14:46:10 +010017#include "src/ostreams.h"
18
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000019#include "src/compiler/wasm-compiler.h"
20
21namespace v8 {
22namespace internal {
23namespace wasm {
24
25#if DEBUG
26#define TRACE(...) \
27 do { \
28 if (FLAG_trace_wasm_decoder) PrintF(__VA_ARGS__); \
29 } while (false)
30#else
31#define TRACE(...)
32#endif
33
34// The root of a decoded tree.
35struct Tree {
36 LocalType type; // tree type.
37 uint32_t count; // number of children.
38 const byte* pc; // start of the syntax tree.
39 TFNode* node; // node in the TurboFan graph.
40 Tree* children[1]; // pointers to children.
41
42 WasmOpcode opcode() const { return static_cast<WasmOpcode>(*pc); }
43};
44
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000045// An SsaEnv environment carries the current local variable renaming
46// as well as the current effect and control dependency in the TF graph.
47// It maintains a control state that tracks whether the environment
48// is reachable, has reached a control end, or has been merged.
49struct SsaEnv {
50 enum State { kControlEnd, kUnreachable, kReached, kMerged };
51
52 State state;
53 TFNode* control;
54 TFNode* effect;
55 TFNode** locals;
56
57 bool go() { return state >= kReached; }
58 void Kill(State new_state = kControlEnd) {
59 state = new_state;
60 locals = nullptr;
61 control = nullptr;
62 effect = nullptr;
63 }
Ben Murdochc5610432016-08-08 18:44:38 +010064 void SetNotMerged() {
65 if (state == kMerged) state = kReached;
66 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000067};
68
Ben Murdochc5610432016-08-08 18:44:38 +010069// An entry on the value stack.
70struct Value {
71 const byte* pc;
72 TFNode* node;
73 LocalType type;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000074};
75
Ben Murdochc5610432016-08-08 18:44:38 +010076// An entry on the control stack (i.e. if, block, loop).
77struct Control {
78 const byte* pc;
79 int stack_depth; // stack height at the beginning of the construct.
80 SsaEnv* end_env; // end environment for the construct.
81 SsaEnv* false_env; // false environment (only for if).
82 TFNode* node; // result node for the construct.
83 LocalType type; // result type for the construct.
84 bool is_loop; // true if this is the inner label of a loop.
85
86 bool is_if() { return *pc == kExprIf; }
87 bool is_block() { return *pc == kExprBlock; }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000088};
89
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000090// Macros that build nodes only if there is a graph and the current SSA
91// environment is reachable from start. This avoids problems with malformed
92// TF graphs when decoding inputs that have unreachable code.
93#define BUILD(func, ...) (build() ? builder_->func(__VA_ARGS__) : nullptr)
94#define BUILD0(func) (build() ? builder_->func() : nullptr)
95
Ben Murdoch097c5b22016-05-18 11:27:45 +010096// Generic Wasm bytecode decoder with utilities for decoding operands,
97// lengths, etc.
98class WasmDecoder : public Decoder {
99 public:
Ben Murdochda12d292016-06-02 14:46:10 +0100100 WasmDecoder(ModuleEnv* module, FunctionSig* sig, const byte* start,
101 const byte* end)
102 : Decoder(start, end),
103 module_(module),
104 sig_(sig),
105 total_locals_(0),
106 local_types_(nullptr) {}
107 ModuleEnv* module_;
108 FunctionSig* sig_;
109 size_t total_locals_;
110 ZoneVector<LocalType>* local_types_;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100111
112 byte ByteOperand(const byte* pc, const char* msg = "missing 1-byte operand") {
113 if ((pc + sizeof(byte)) >= limit_) {
114 error(pc, msg);
115 return 0;
116 }
117 return pc[1];
118 }
119
120 uint32_t Uint32Operand(const byte* pc) {
121 if ((pc + sizeof(uint32_t)) >= limit_) {
122 error(pc, "missing 4-byte operand");
123 return 0;
124 }
125 return read_u32(pc + 1);
126 }
127
128 uint64_t Uint64Operand(const byte* pc) {
129 if ((pc + sizeof(uint64_t)) >= limit_) {
130 error(pc, "missing 8-byte operand");
131 return 0;
132 }
133 return read_u64(pc + 1);
134 }
135
136 inline bool Validate(const byte* pc, LocalIndexOperand& operand) {
Ben Murdochda12d292016-06-02 14:46:10 +0100137 if (operand.index < total_locals_) {
138 if (local_types_) {
139 operand.type = local_types_->at(operand.index);
140 } else {
141 operand.type = kAstStmt;
142 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100143 return true;
144 }
145 error(pc, pc + 1, "invalid local index");
146 return false;
147 }
148
149 inline bool Validate(const byte* pc, GlobalIndexOperand& operand) {
Ben Murdochda12d292016-06-02 14:46:10 +0100150 ModuleEnv* m = module_;
151 if (m && m->module && operand.index < m->module->globals.size()) {
152 operand.machine_type = m->module->globals[operand.index].type;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100153 operand.type = WasmOpcodes::LocalTypeFor(operand.machine_type);
154 return true;
155 }
156 error(pc, pc + 1, "invalid global index");
157 return false;
158 }
159
Ben Murdochc5610432016-08-08 18:44:38 +0100160 inline bool Validate(const byte* pc, CallFunctionOperand& operand) {
Ben Murdochda12d292016-06-02 14:46:10 +0100161 ModuleEnv* m = module_;
162 if (m && m->module && operand.index < m->module->functions.size()) {
163 operand.sig = m->module->functions[operand.index].sig;
Ben Murdochc5610432016-08-08 18:44:38 +0100164 uint32_t expected = static_cast<uint32_t>(operand.sig->parameter_count());
165 if (operand.arity != expected) {
166 error(pc, pc + 1,
167 "arity mismatch in direct function call (expected %u, got %u)",
168 expected, operand.arity);
169 return false;
170 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100171 return true;
172 }
173 error(pc, pc + 1, "invalid function index");
174 return false;
175 }
176
Ben Murdochc5610432016-08-08 18:44:38 +0100177 inline bool Validate(const byte* pc, CallIndirectOperand& operand) {
Ben Murdochda12d292016-06-02 14:46:10 +0100178 ModuleEnv* m = module_;
179 if (m && m->module && operand.index < m->module->signatures.size()) {
180 operand.sig = m->module->signatures[operand.index];
Ben Murdochc5610432016-08-08 18:44:38 +0100181 uint32_t expected = static_cast<uint32_t>(operand.sig->parameter_count());
182 if (operand.arity != expected) {
183 error(pc, pc + 1,
184 "arity mismatch in indirect function call (expected %u, got %u)",
185 expected, operand.arity);
186 return false;
187 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100188 return true;
189 }
190 error(pc, pc + 1, "invalid signature index");
191 return false;
192 }
193
Ben Murdochc5610432016-08-08 18:44:38 +0100194 inline bool Validate(const byte* pc, CallImportOperand& operand) {
Ben Murdochda12d292016-06-02 14:46:10 +0100195 ModuleEnv* m = module_;
196 if (m && m->module && operand.index < m->module->import_table.size()) {
197 operand.sig = m->module->import_table[operand.index].sig;
Ben Murdochc5610432016-08-08 18:44:38 +0100198 uint32_t expected = static_cast<uint32_t>(operand.sig->parameter_count());
199 if (operand.arity != expected) {
200 error(pc, pc + 1, "arity mismatch in import call (expected %u, got %u)",
201 expected, operand.arity);
202 return false;
203 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100204 return true;
205 }
206 error(pc, pc + 1, "invalid signature index");
207 return false;
208 }
209
210 inline bool Validate(const byte* pc, BreakDepthOperand& operand,
Ben Murdochc5610432016-08-08 18:44:38 +0100211 ZoneVector<Control>& control) {
212 if (operand.arity > 1) {
213 error(pc, pc + 1, "invalid arity for br or br_if");
214 return false;
215 }
216 if (operand.depth < control.size()) {
217 operand.target = &control[control.size() - operand.depth - 1];
Ben Murdoch097c5b22016-05-18 11:27:45 +0100218 return true;
219 }
220 error(pc, pc + 1, "invalid break depth");
221 return false;
222 }
223
Ben Murdochda12d292016-06-02 14:46:10 +0100224 bool Validate(const byte* pc, BranchTableOperand& operand,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100225 size_t block_depth) {
Ben Murdochc5610432016-08-08 18:44:38 +0100226 if (operand.arity > 1) {
227 error(pc, pc + 1, "invalid arity for break");
228 return false;
229 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100230 // Verify table.
Ben Murdochda12d292016-06-02 14:46:10 +0100231 for (uint32_t i = 0; i < operand.table_count + 1; i++) {
232 uint32_t target = operand.read_entry(this, i);
233 if (target >= block_depth) {
234 error(operand.table + i * 2, "improper branch in br_table");
235 return false;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100236 }
237 }
238 return true;
239 }
240
241 int OpcodeArity(const byte* pc) {
242#define DECLARE_ARITY(name, ...) \
243 static const LocalType kTypes_##name[] = {__VA_ARGS__}; \
244 static const int kArity_##name = \
245 static_cast<int>(arraysize(kTypes_##name) - 1);
246
247 FOREACH_SIGNATURE(DECLARE_ARITY);
248#undef DECLARE_ARITY
249
250 switch (static_cast<WasmOpcode>(*pc)) {
251 case kExprI8Const:
252 case kExprI32Const:
253 case kExprI64Const:
254 case kExprF64Const:
255 case kExprF32Const:
256 case kExprGetLocal:
257 case kExprLoadGlobal:
258 case kExprNop:
259 case kExprUnreachable:
Ben Murdochc5610432016-08-08 18:44:38 +0100260 case kExprEnd:
261 case kExprBlock:
262 case kExprLoop:
Ben Murdoch097c5b22016-05-18 11:27:45 +0100263 return 0;
264
Ben Murdoch097c5b22016-05-18 11:27:45 +0100265 case kExprStoreGlobal:
266 case kExprSetLocal:
Ben Murdochc5610432016-08-08 18:44:38 +0100267 case kExprElse:
Ben Murdoch097c5b22016-05-18 11:27:45 +0100268 return 1;
269
Ben Murdochc5610432016-08-08 18:44:38 +0100270 case kExprBr: {
271 BreakDepthOperand operand(this, pc);
272 return operand.arity;
273 }
274 case kExprBrIf: {
275 BreakDepthOperand operand(this, pc);
276 return 1 + operand.arity;
277 }
278 case kExprBrTable: {
279 BranchTableOperand operand(this, pc);
280 return 1 + operand.arity;
281 }
282
Ben Murdoch097c5b22016-05-18 11:27:45 +0100283 case kExprIf:
Ben Murdochc5610432016-08-08 18:44:38 +0100284 return 1;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100285 case kExprSelect:
286 return 3;
287
Ben Murdoch097c5b22016-05-18 11:27:45 +0100288 case kExprCallFunction: {
Ben Murdochc5610432016-08-08 18:44:38 +0100289 CallFunctionOperand operand(this, pc);
290 return operand.arity;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100291 }
292 case kExprCallIndirect: {
Ben Murdochc5610432016-08-08 18:44:38 +0100293 CallIndirectOperand operand(this, pc);
294 return 1 + operand.arity;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100295 }
296 case kExprCallImport: {
Ben Murdochc5610432016-08-08 18:44:38 +0100297 CallImportOperand operand(this, pc);
298 return operand.arity;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100299 }
300 case kExprReturn: {
Ben Murdochc5610432016-08-08 18:44:38 +0100301 ReturnArityOperand operand(this, pc);
302 return operand.arity;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100303 }
304
305#define DECLARE_OPCODE_CASE(name, opcode, sig) \
306 case kExpr##name: \
307 return kArity_##sig;
308
309 FOREACH_LOAD_MEM_OPCODE(DECLARE_OPCODE_CASE)
310 FOREACH_STORE_MEM_OPCODE(DECLARE_OPCODE_CASE)
311 FOREACH_MISC_MEM_OPCODE(DECLARE_OPCODE_CASE)
312 FOREACH_SIMPLE_OPCODE(DECLARE_OPCODE_CASE)
Ben Murdochda12d292016-06-02 14:46:10 +0100313 FOREACH_ASMJS_COMPAT_OPCODE(DECLARE_OPCODE_CASE)
Ben Murdoch097c5b22016-05-18 11:27:45 +0100314#undef DECLARE_OPCODE_CASE
Ben Murdochda12d292016-06-02 14:46:10 +0100315 default:
316 UNREACHABLE();
317 return 0;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100318 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100319 }
320
321 int OpcodeLength(const byte* pc) {
322 switch (static_cast<WasmOpcode>(*pc)) {
323#define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name:
324 FOREACH_LOAD_MEM_OPCODE(DECLARE_OPCODE_CASE)
325 FOREACH_STORE_MEM_OPCODE(DECLARE_OPCODE_CASE)
326#undef DECLARE_OPCODE_CASE
327 {
328 MemoryAccessOperand operand(this, pc);
329 return 1 + operand.length;
330 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100331 case kExprBr:
332 case kExprBrIf: {
333 BreakDepthOperand operand(this, pc);
334 return 1 + operand.length;
335 }
336 case kExprStoreGlobal:
337 case kExprLoadGlobal: {
338 GlobalIndexOperand operand(this, pc);
339 return 1 + operand.length;
340 }
341
342 case kExprCallFunction: {
Ben Murdochc5610432016-08-08 18:44:38 +0100343 CallFunctionOperand operand(this, pc);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100344 return 1 + operand.length;
345 }
346 case kExprCallIndirect: {
Ben Murdochc5610432016-08-08 18:44:38 +0100347 CallIndirectOperand operand(this, pc);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100348 return 1 + operand.length;
349 }
350 case kExprCallImport: {
Ben Murdochc5610432016-08-08 18:44:38 +0100351 CallImportOperand operand(this, pc);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100352 return 1 + operand.length;
353 }
354
355 case kExprSetLocal:
356 case kExprGetLocal: {
357 LocalIndexOperand operand(this, pc);
358 return 1 + operand.length;
359 }
Ben Murdochda12d292016-06-02 14:46:10 +0100360 case kExprBrTable: {
361 BranchTableOperand operand(this, pc);
362 return 1 + operand.length;
363 }
364 case kExprI32Const: {
365 ImmI32Operand operand(this, pc);
366 return 1 + operand.length;
367 }
368 case kExprI64Const: {
369 ImmI64Operand operand(this, pc);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100370 return 1 + operand.length;
371 }
372 case kExprI8Const:
373 return 2;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100374 case kExprF32Const:
375 return 5;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100376 case kExprF64Const:
377 return 9;
Ben Murdochc5610432016-08-08 18:44:38 +0100378 case kExprReturn: {
379 ReturnArityOperand operand(this, pc);
380 return 1 + operand.length;
381 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100382
383 default:
384 return 1;
385 }
386 }
387};
388
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000389// A shift-reduce-parser strategy for decoding Wasm code that uses an explicit
390// shift-reduce strategy with multiple internal stacks.
Ben Murdochda12d292016-06-02 14:46:10 +0100391class SR_WasmDecoder : public WasmDecoder {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000392 public:
Ben Murdochda12d292016-06-02 14:46:10 +0100393 SR_WasmDecoder(Zone* zone, TFBuilder* builder, FunctionBody& body)
394 : WasmDecoder(body.module, body.sig, body.start, body.end),
395 zone_(zone),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000396 builder_(builder),
Ben Murdochda12d292016-06-02 14:46:10 +0100397 base_(body.base),
398 local_type_vec_(zone),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000399 stack_(zone),
Ben Murdochc5610432016-08-08 18:44:38 +0100400 control_(zone) {
Ben Murdochda12d292016-06-02 14:46:10 +0100401 local_types_ = &local_type_vec_;
402 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000403
Ben Murdochc5610432016-08-08 18:44:38 +0100404 bool Decode() {
405 base::ElapsedTimer decode_timer;
406 if (FLAG_trace_wasm_decode_time) {
407 decode_timer.Start();
408 }
409 stack_.clear();
410 control_.clear();
411
Ben Murdochda12d292016-06-02 14:46:10 +0100412 if (end_ < pc_) {
413 error(pc_, "function body end < start");
Ben Murdochc5610432016-08-08 18:44:38 +0100414 return false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000415 }
416
Ben Murdochda12d292016-06-02 14:46:10 +0100417 DecodeLocalDecls();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000418 InitSsaEnv();
419 DecodeFunctionBody();
420
Ben Murdochc5610432016-08-08 18:44:38 +0100421 if (failed()) return TraceFailed();
422
423 if (!control_.empty()) {
424 error(pc_, control_.back().pc, "unterminated control structure");
425 return TraceFailed();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000426 }
427
Ben Murdochc5610432016-08-08 18:44:38 +0100428 if (ssa_env_->go()) {
429 TRACE(" @%-6d #xx:%-20s|", startrel(pc_), "ImplicitReturn");
430 DoReturn();
431 if (failed()) return TraceFailed();
432 TRACE("\n");
433 }
434
435 if (FLAG_trace_wasm_decode_time) {
436 double ms = decode_timer.Elapsed().InMillisecondsF();
437 PrintF("wasm-decode ok (%0.3f ms)\n\n", ms);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000438 } else {
Ben Murdochc5610432016-08-08 18:44:38 +0100439 TRACE("wasm-decode ok\n\n");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000440 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100441
Ben Murdochc5610432016-08-08 18:44:38 +0100442 return true;
443 }
444
445 bool TraceFailed() {
446 TRACE("wasm-error module+%-6d func+%d: %s\n\n", baserel(error_pc_),
447 startrel(error_pc_), error_msg_.get());
448 return false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000449 }
450
Ben Murdochda12d292016-06-02 14:46:10 +0100451 bool DecodeLocalDecls(AstLocalDecls& decls) {
452 DecodeLocalDecls();
453 if (failed()) return false;
454 decls.decls_encoded_size = pc_offset();
Ben Murdochda12d292016-06-02 14:46:10 +0100455 decls.local_types.reserve(local_type_vec_.size());
456 for (size_t pos = 0; pos < local_type_vec_.size();) {
457 uint32_t count = 0;
458 LocalType type = local_type_vec_[pos];
459 while (pos < local_type_vec_.size() && local_type_vec_[pos] == type) {
460 pos++;
461 count++;
462 }
Ben Murdochda12d292016-06-02 14:46:10 +0100463 decls.local_types.push_back(std::pair<LocalType, uint32_t>(type, count));
464 }
Ben Murdochc5610432016-08-08 18:44:38 +0100465 decls.total_local_count = static_cast<uint32_t>(local_type_vec_.size());
Ben Murdochda12d292016-06-02 14:46:10 +0100466 return true;
467 }
468
469 BitVector* AnalyzeLoopAssignmentForTesting(const byte* pc,
470 size_t num_locals) {
471 total_locals_ = num_locals;
472 local_type_vec_.reserve(num_locals);
473 if (num_locals > local_type_vec_.size()) {
474 local_type_vec_.insert(local_type_vec_.end(),
475 num_locals - local_type_vec_.size(), kAstI32);
476 }
477 return AnalyzeLoopAssignment(pc);
478 }
479
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000480 private:
481 static const size_t kErrorMsgSize = 128;
482
483 Zone* zone_;
484 TFBuilder* builder_;
485 const byte* base_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000486
487 SsaEnv* ssa_env_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000488
Ben Murdochc5610432016-08-08 18:44:38 +0100489 ZoneVector<LocalType> local_type_vec_; // types of local variables.
490 ZoneVector<Value> stack_; // stack of values.
491 ZoneVector<Control> control_; // stack of blocks, loops, and ifs.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000492
493 inline bool build() { return builder_ && ssa_env_->go(); }
494
495 void InitSsaEnv() {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000496 TFNode* start = nullptr;
497 SsaEnv* ssa_env = reinterpret_cast<SsaEnv*>(zone_->New(sizeof(SsaEnv)));
498 size_t size = sizeof(TFNode*) * EnvironmentCount();
499 ssa_env->state = SsaEnv::kReached;
500 ssa_env->locals =
501 size > 0 ? reinterpret_cast<TFNode**>(zone_->New(size)) : nullptr;
502
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000503 if (builder_) {
Ben Murdochda12d292016-06-02 14:46:10 +0100504 start = builder_->Start(static_cast<int>(sig_->parameter_count() + 1));
505 // Initialize local variables.
506 uint32_t index = 0;
507 while (index < sig_->parameter_count()) {
508 ssa_env->locals[index] = builder_->Param(index, local_type_vec_[index]);
509 index++;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000510 }
Ben Murdochda12d292016-06-02 14:46:10 +0100511 while (index < local_type_vec_.size()) {
512 LocalType type = local_type_vec_[index];
513 TFNode* node = DefaultValue(type);
514 while (index < local_type_vec_.size() &&
515 local_type_vec_[index] == type) {
516 // Do a whole run of like-typed locals at a time.
517 ssa_env->locals[index++] = node;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000518 }
519 }
Ben Murdochda12d292016-06-02 14:46:10 +0100520 builder_->set_module(module_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000521 }
522 ssa_env->control = start;
523 ssa_env->effect = start;
524 SetEnv("initial", ssa_env);
525 }
526
Ben Murdochda12d292016-06-02 14:46:10 +0100527 TFNode* DefaultValue(LocalType type) {
528 switch (type) {
529 case kAstI32:
530 return builder_->Int32Constant(0);
531 case kAstI64:
532 return builder_->Int64Constant(0);
533 case kAstF32:
534 return builder_->Float32Constant(0);
535 case kAstF64:
536 return builder_->Float64Constant(0);
537 default:
538 UNREACHABLE();
539 return nullptr;
540 }
541 }
542
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000543 char* indentation() {
544 static const int kMaxIndent = 64;
545 static char bytes[kMaxIndent + 1];
546 for (int i = 0; i < kMaxIndent; i++) bytes[i] = ' ';
547 bytes[kMaxIndent] = 0;
548 if (stack_.size() < kMaxIndent / 2) {
549 bytes[stack_.size() * 2] = 0;
550 }
551 return bytes;
552 }
553
Ben Murdochda12d292016-06-02 14:46:10 +0100554 // Decodes the locals declarations, if any, populating {local_type_vec_}.
555 void DecodeLocalDecls() {
556 DCHECK_EQ(0, local_type_vec_.size());
557 // Initialize {local_type_vec} from signature.
558 if (sig_) {
559 local_type_vec_.reserve(sig_->parameter_count());
560 for (size_t i = 0; i < sig_->parameter_count(); i++) {
561 local_type_vec_.push_back(sig_->GetParam(i));
562 }
563 }
564 // Decode local declarations, if any.
565 int length;
566 uint32_t entries = consume_u32v(&length, "local decls count");
567 while (entries-- > 0 && pc_ < limit_) {
568 uint32_t count = consume_u32v(&length, "local count");
569 byte code = consume_u8("local type");
570 LocalType type;
571 switch (code) {
572 case kLocalI32:
573 type = kAstI32;
574 break;
575 case kLocalI64:
576 type = kAstI64;
577 break;
578 case kLocalF32:
579 type = kAstF32;
580 break;
581 case kLocalF64:
582 type = kAstF64;
583 break;
584 default:
585 error(pc_ - 1, "invalid local type");
586 return;
587 }
588 local_type_vec_.insert(local_type_vec_.end(), count, type);
589 }
590 total_locals_ = local_type_vec_.size();
591 }
592
Ben Murdochc5610432016-08-08 18:44:38 +0100593 // Decodes the body of a function.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000594 void DecodeFunctionBody() {
Ben Murdochc5610432016-08-08 18:44:38 +0100595 TRACE("wasm-decode %p...%p (module+%d, %d bytes) %s\n",
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000596 reinterpret_cast<const void*>(start_),
Ben Murdochc5610432016-08-08 18:44:38 +0100597 reinterpret_cast<const void*>(limit_), baserel(pc_),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000598 static_cast<int>(limit_ - start_), builder_ ? "graph building" : "");
599
600 if (pc_ >= limit_) return; // Nothing to do.
601
602 while (true) { // decoding loop.
603 int len = 1;
604 WasmOpcode opcode = static_cast<WasmOpcode>(*pc_);
Ben Murdochc5610432016-08-08 18:44:38 +0100605 TRACE(" @%-6d #%02x:%-20s|", startrel(pc_), opcode,
606 WasmOpcodes::ShortOpcodeName(opcode));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000607
608 FunctionSig* sig = WasmOpcodes::Signature(opcode);
609 if (sig) {
Ben Murdochc5610432016-08-08 18:44:38 +0100610 // Fast case of a simple operator.
611 TFNode* node;
612 switch (sig->parameter_count()) {
613 case 1: {
614 Value val = Pop(0, sig->GetParam(0));
615 node = BUILD(Unop, opcode, val.node, position());
616 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000617 }
Ben Murdochc5610432016-08-08 18:44:38 +0100618 case 2: {
619 Value rval = Pop(1, sig->GetParam(1));
620 Value lval = Pop(0, sig->GetParam(0));
621 node = BUILD(Binop, opcode, lval.node, rval.node, position());
622 break;
623 }
624 default:
625 UNREACHABLE();
626 node = nullptr;
627 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000628 }
Ben Murdochc5610432016-08-08 18:44:38 +0100629 Push(GetReturnType(sig), node);
630 } else {
631 // Complex bytecode.
632 switch (opcode) {
633 case kExprNop:
634 Push(kAstStmt, nullptr);
635 break;
636 case kExprBlock: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000637 // The break environment is the outer environment.
638 SsaEnv* break_env = ssa_env_;
639 PushBlock(break_env);
640 SetEnv("block:start", Steal(break_env));
Ben Murdochc5610432016-08-08 18:44:38 +0100641 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000642 }
Ben Murdochc5610432016-08-08 18:44:38 +0100643 case kExprLoop: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000644 // The break environment is the outer environment.
645 SsaEnv* break_env = ssa_env_;
646 PushBlock(break_env);
647 SsaEnv* cont_env = Steal(break_env);
648 // The continue environment is the inner environment.
Ben Murdochda12d292016-06-02 14:46:10 +0100649 PrepareForLoop(pc_, cont_env);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000650 SetEnv("loop:start", Split(cont_env));
Ben Murdochc5610432016-08-08 18:44:38 +0100651 ssa_env_->SetNotMerged();
652 PushLoop(cont_env);
653 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000654 }
Ben Murdochc5610432016-08-08 18:44:38 +0100655 case kExprIf: {
656 // Condition on top of stack. Split environments for branches.
657 Value cond = Pop(0, kAstI32);
658 TFNode* if_true = nullptr;
659 TFNode* if_false = nullptr;
660 BUILD(Branch, cond.node, &if_true, &if_false);
661 SsaEnv* end_env = ssa_env_;
662 SsaEnv* false_env = Split(ssa_env_);
663 false_env->control = if_false;
664 SsaEnv* true_env = Steal(ssa_env_);
665 true_env->control = if_true;
666 PushIf(end_env, false_env);
667 SetEnv("if:true", true_env);
668 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000669 }
Ben Murdochc5610432016-08-08 18:44:38 +0100670 case kExprElse: {
671 if (control_.empty()) {
672 error(pc_, "else does not match any if");
673 break;
674 }
675 Control* c = &control_.back();
676 if (!c->is_if()) {
677 error(pc_, c->pc, "else does not match an if");
678 break;
679 }
680 if (c->false_env == nullptr) {
681 error(pc_, c->pc, "else already present for if");
682 break;
683 }
684 Value val = PopUpTo(c->stack_depth);
685 MergeInto(c->end_env, &c->node, &c->type, val);
686 // Switch to environment for false branch.
687 SetEnv("if_else:false", c->false_env);
688 c->false_env = nullptr; // record that an else is already seen
689 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000690 }
Ben Murdochc5610432016-08-08 18:44:38 +0100691 case kExprEnd: {
692 if (control_.empty()) {
693 error(pc_, "end does not match any if or block");
694 break;
695 }
696 const char* name = "block:end";
697 Control* c = &control_.back();
698 if (c->is_loop) {
699 // Loops always push control in pairs.
700 control_.pop_back();
701 c = &control_.back();
702 name = "loop:end";
703 }
704 Value val = PopUpTo(c->stack_depth);
705 if (c->is_if()) {
706 if (c->false_env != nullptr) {
707 // End the true branch of a one-armed if.
708 Goto(c->false_env, c->end_env);
709 val = {val.pc, nullptr, kAstStmt};
710 name = "if:merge";
711 } else {
712 // End the false branch of a two-armed if.
713 name = "if_else:merge";
714 }
715 }
716 if (ssa_env_->go()) {
717 MergeInto(c->end_env, &c->node, &c->type, val);
718 }
719 SetEnv(name, c->end_env);
720 stack_.resize(c->stack_depth);
721 Push(c->type, c->node);
722 control_.pop_back();
723 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000724 }
Ben Murdochc5610432016-08-08 18:44:38 +0100725 case kExprSelect: {
726 Value cond = Pop(2, kAstI32);
727 Value fval = Pop();
728 Value tval = Pop();
729 if (tval.type == kAstStmt || tval.type != fval.type) {
730 if (tval.type != kAstEnd && fval.type != kAstEnd) {
731 error(pc_, "type mismatch in select");
732 break;
733 }
734 }
735 if (build()) {
736 DCHECK(tval.type != kAstEnd);
737 DCHECK(fval.type != kAstEnd);
738 DCHECK(cond.type != kAstEnd);
739 TFNode* controls[2];
740 builder_->Branch(cond.node, &controls[0], &controls[1]);
741 TFNode* merge = builder_->Merge(2, controls);
742 TFNode* vals[2] = {tval.node, fval.node};
743 TFNode* phi = builder_->Phi(tval.type, 2, vals, merge);
744 Push(tval.type, phi);
745 ssa_env_->control = merge;
746 } else {
747 Push(tval.type, nullptr);
748 }
749 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000750 }
Ben Murdochc5610432016-08-08 18:44:38 +0100751 case kExprBr: {
752 BreakDepthOperand operand(this, pc_);
753 Value val = {pc_, nullptr, kAstStmt};
754 if (operand.arity) val = Pop();
755 if (Validate(pc_, operand, control_)) {
756 BreakTo(operand.target, val);
757 }
758 len = 1 + operand.length;
759 Push(kAstEnd, nullptr);
760 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100761 }
Ben Murdochc5610432016-08-08 18:44:38 +0100762 case kExprBrIf: {
763 BreakDepthOperand operand(this, pc_);
764 Value cond = Pop(operand.arity, kAstI32);
765 Value val = {pc_, nullptr, kAstStmt};
766 if (operand.arity == 1) val = Pop();
767 if (Validate(pc_, operand, control_)) {
768 SsaEnv* fenv = ssa_env_;
769 SsaEnv* tenv = Split(fenv);
770 fenv->SetNotMerged();
771 BUILD(Branch, cond.node, &tenv->control, &fenv->control);
772 ssa_env_ = tenv;
773 BreakTo(operand.target, val);
774 ssa_env_ = fenv;
775 }
776 len = 1 + operand.length;
777 Push(kAstStmt, nullptr);
778 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100779 }
Ben Murdochc5610432016-08-08 18:44:38 +0100780 case kExprBrTable: {
781 BranchTableOperand operand(this, pc_);
782 if (Validate(pc_, operand, control_.size())) {
783 Value key = Pop(operand.arity, kAstI32);
784 Value val = {pc_, nullptr, kAstStmt};
785 if (operand.arity == 1) val = Pop();
786 if (failed()) break;
787
788 SsaEnv* break_env = ssa_env_;
789 if (operand.table_count > 0) {
790 // Build branches to the various blocks based on the table.
791 TFNode* sw = BUILD(Switch, operand.table_count + 1, key.node);
792
793 SsaEnv* copy = Steal(break_env);
794 ssa_env_ = copy;
795 for (uint32_t i = 0; i < operand.table_count + 1; i++) {
796 uint16_t target = operand.read_entry(this, i);
797 ssa_env_ = Split(copy);
798 ssa_env_->control = (i == operand.table_count)
799 ? BUILD(IfDefault, sw)
800 : BUILD(IfValue, i, sw);
801 int depth = target;
802 Control* c = &control_[control_.size() - depth - 1];
803 MergeInto(c->end_env, &c->node, &c->type, val);
804 }
805 } else {
806 // Only a default target. Do the equivalent of br.
807 uint16_t target = operand.read_entry(this, 0);
808 int depth = target;
809 Control* c = &control_[control_.size() - depth - 1];
810 MergeInto(c->end_env, &c->node, &c->type, val);
811 }
812 // br_table ends the control flow like br.
813 ssa_env_ = break_env;
814 Push(kAstStmt, nullptr);
815 }
816 len = 1 + operand.length;
817 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100818 }
Ben Murdochc5610432016-08-08 18:44:38 +0100819 case kExprReturn: {
820 ReturnArityOperand operand(this, pc_);
821 if (operand.arity != sig_->return_count()) {
822 error(pc_, pc_ + 1, "arity mismatch in return");
823 }
824 DoReturn();
825 len = 1 + operand.length;
826 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100827 }
Ben Murdochc5610432016-08-08 18:44:38 +0100828 case kExprUnreachable: {
829 Push(kAstEnd, BUILD(Unreachable, position()));
830 ssa_env_->Kill(SsaEnv::kControlEnd);
831 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000832 }
Ben Murdochc5610432016-08-08 18:44:38 +0100833 case kExprI8Const: {
834 ImmI8Operand operand(this, pc_);
835 Push(kAstI32, BUILD(Int32Constant, operand.value));
836 len = 1 + operand.length;
837 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000838 }
Ben Murdochc5610432016-08-08 18:44:38 +0100839 case kExprI32Const: {
840 ImmI32Operand operand(this, pc_);
841 Push(kAstI32, BUILD(Int32Constant, operand.value));
842 len = 1 + operand.length;
843 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100844 }
Ben Murdochc5610432016-08-08 18:44:38 +0100845 case kExprI64Const: {
846 ImmI64Operand operand(this, pc_);
847 Push(kAstI64, BUILD(Int64Constant, operand.value));
848 len = 1 + operand.length;
849 break;
850 }
851 case kExprF32Const: {
852 ImmF32Operand operand(this, pc_);
853 Push(kAstF32, BUILD(Float32Constant, operand.value));
854 len = 1 + operand.length;
855 break;
856 }
857 case kExprF64Const: {
858 ImmF64Operand operand(this, pc_);
859 Push(kAstF64, BUILD(Float64Constant, operand.value));
860 len = 1 + operand.length;
861 break;
862 }
863 case kExprGetLocal: {
864 LocalIndexOperand operand(this, pc_);
865 if (Validate(pc_, operand)) {
866 if (build()) {
867 Push(operand.type, ssa_env_->locals[operand.index]);
868 } else {
869 Push(operand.type, nullptr);
870 }
871 }
872 len = 1 + operand.length;
873 break;
874 }
875 case kExprSetLocal: {
876 LocalIndexOperand operand(this, pc_);
877 if (Validate(pc_, operand)) {
878 Value val = Pop(0, local_type_vec_[operand.index]);
879 if (ssa_env_->locals) ssa_env_->locals[operand.index] = val.node;
880 Push(val.type, val.node);
881 }
882 len = 1 + operand.length;
883 break;
884 }
885 case kExprLoadGlobal: {
886 GlobalIndexOperand operand(this, pc_);
887 if (Validate(pc_, operand)) {
888 Push(operand.type, BUILD(LoadGlobal, operand.index));
889 }
890 len = 1 + operand.length;
891 break;
892 }
893 case kExprStoreGlobal: {
894 GlobalIndexOperand operand(this, pc_);
895 if (Validate(pc_, operand)) {
896 Value val = Pop(0, operand.type);
897 BUILD(StoreGlobal, operand.index, val.node);
898 Push(val.type, val.node);
899 }
900 len = 1 + operand.length;
901 break;
902 }
903 case kExprI32LoadMem8S:
904 len = DecodeLoadMem(kAstI32, MachineType::Int8());
905 break;
906 case kExprI32LoadMem8U:
907 len = DecodeLoadMem(kAstI32, MachineType::Uint8());
908 break;
909 case kExprI32LoadMem16S:
910 len = DecodeLoadMem(kAstI32, MachineType::Int16());
911 break;
912 case kExprI32LoadMem16U:
913 len = DecodeLoadMem(kAstI32, MachineType::Uint16());
914 break;
915 case kExprI32LoadMem:
916 len = DecodeLoadMem(kAstI32, MachineType::Int32());
917 break;
918
919 case kExprI64LoadMem8S:
920 len = DecodeLoadMem(kAstI64, MachineType::Int8());
921 break;
922 case kExprI64LoadMem8U:
923 len = DecodeLoadMem(kAstI64, MachineType::Uint8());
924 break;
925 case kExprI64LoadMem16S:
926 len = DecodeLoadMem(kAstI64, MachineType::Int16());
927 break;
928 case kExprI64LoadMem16U:
929 len = DecodeLoadMem(kAstI64, MachineType::Uint16());
930 break;
931 case kExprI64LoadMem32S:
932 len = DecodeLoadMem(kAstI64, MachineType::Int32());
933 break;
934 case kExprI64LoadMem32U:
935 len = DecodeLoadMem(kAstI64, MachineType::Uint32());
936 break;
937 case kExprI64LoadMem:
938 len = DecodeLoadMem(kAstI64, MachineType::Int64());
939 break;
940 case kExprF32LoadMem:
941 len = DecodeLoadMem(kAstF32, MachineType::Float32());
942 break;
943 case kExprF64LoadMem:
944 len = DecodeLoadMem(kAstF64, MachineType::Float64());
945 break;
946 case kExprI32StoreMem8:
947 len = DecodeStoreMem(kAstI32, MachineType::Int8());
948 break;
949 case kExprI32StoreMem16:
950 len = DecodeStoreMem(kAstI32, MachineType::Int16());
951 break;
952 case kExprI32StoreMem:
953 len = DecodeStoreMem(kAstI32, MachineType::Int32());
954 break;
955 case kExprI64StoreMem8:
956 len = DecodeStoreMem(kAstI64, MachineType::Int8());
957 break;
958 case kExprI64StoreMem16:
959 len = DecodeStoreMem(kAstI64, MachineType::Int16());
960 break;
961 case kExprI64StoreMem32:
962 len = DecodeStoreMem(kAstI64, MachineType::Int32());
963 break;
964 case kExprI64StoreMem:
965 len = DecodeStoreMem(kAstI64, MachineType::Int64());
966 break;
967 case kExprF32StoreMem:
968 len = DecodeStoreMem(kAstF32, MachineType::Float32());
969 break;
970 case kExprF64StoreMem:
971 len = DecodeStoreMem(kAstF64, MachineType::Float64());
972 break;
973
974 case kExprMemorySize:
975 Push(kAstI32, BUILD(MemSize, 0));
976 break;
977 case kExprGrowMemory: {
978 Value val = Pop(0, kAstI32);
979 USE(val); // TODO(titzer): build node for grow memory
980 Push(kAstI32, BUILD(Int32Constant, 0));
981 break;
982 }
983 case kExprCallFunction: {
984 CallFunctionOperand operand(this, pc_);
985 if (Validate(pc_, operand)) {
986 TFNode** buffer = PopArgs(operand.sig);
987 TFNode* call =
988 BUILD(CallDirect, operand.index, buffer, position());
989 Push(GetReturnType(operand.sig), call);
990 }
991 len = 1 + operand.length;
992 break;
993 }
994 case kExprCallIndirect: {
995 CallIndirectOperand operand(this, pc_);
996 if (Validate(pc_, operand)) {
997 TFNode** buffer = PopArgs(operand.sig);
998 Value index = Pop(0, kAstI32);
999 if (buffer) buffer[0] = index.node;
1000 TFNode* call =
1001 BUILD(CallIndirect, operand.index, buffer, position());
1002 Push(GetReturnType(operand.sig), call);
1003 }
1004 len = 1 + operand.length;
1005 break;
1006 }
1007 case kExprCallImport: {
1008 CallImportOperand operand(this, pc_);
1009 if (Validate(pc_, operand)) {
1010 TFNode** buffer = PopArgs(operand.sig);
1011 TFNode* call =
1012 BUILD(CallImport, operand.index, buffer, position());
1013 Push(GetReturnType(operand.sig), call);
1014 }
1015 len = 1 + operand.length;
1016 break;
1017 }
1018 default:
1019 error("Invalid opcode");
1020 return;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001021 }
Ben Murdochc5610432016-08-08 18:44:38 +01001022 } // end complex bytecode
1023
1024#if DEBUG
1025 if (FLAG_trace_wasm_decoder) {
1026 for (size_t i = 0; i < stack_.size(); i++) {
1027 Value& val = stack_[i];
1028 WasmOpcode opcode = static_cast<WasmOpcode>(*val.pc);
1029 PrintF(" %c@%d:%s", WasmOpcodes::ShortNameOf(val.type),
1030 static_cast<int>(val.pc - start_),
1031 WasmOpcodes::ShortOpcodeName(opcode));
1032 switch (opcode) {
1033 case kExprI32Const: {
1034 ImmI32Operand operand(this, val.pc);
1035 PrintF("[%d]", operand.value);
1036 break;
1037 }
1038 case kExprGetLocal: {
1039 LocalIndexOperand operand(this, val.pc);
1040 PrintF("[%u]", operand.index);
1041 break;
1042 }
1043 case kExprSetLocal: {
1044 LocalIndexOperand operand(this, val.pc);
1045 PrintF("[%u]", operand.index);
1046 break;
1047 }
1048 default:
1049 break;
1050 }
1051 }
1052 PrintF("\n");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001053 }
Ben Murdochc5610432016-08-08 18:44:38 +01001054#endif
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001055 pc_ += len;
1056 if (pc_ >= limit_) {
1057 // End of code reached or exceeded.
Ben Murdochc5610432016-08-08 18:44:38 +01001058 if (pc_ > limit_ && ok()) error("Beyond end of code");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001059 return;
1060 }
Ben Murdochc5610432016-08-08 18:44:38 +01001061 } // end decode loop
1062 } // end DecodeFunctionBody()
1063
1064 TFNode** PopArgs(FunctionSig* sig) {
1065 if (build()) {
1066 int count = static_cast<int>(sig->parameter_count());
1067 TFNode** buffer = builder_->Buffer(count + 1);
1068 buffer[0] = nullptr; // reserved for code object or function index.
1069 for (int i = count - 1; i >= 0; i--) {
1070 buffer[i + 1] = Pop(i, sig->GetParam(i)).node;
1071 }
1072 return buffer;
1073 } else {
1074 int count = static_cast<int>(sig->parameter_count());
1075 for (int i = count - 1; i >= 0; i--) {
1076 Pop(i, sig->GetParam(i));
1077 }
1078 return nullptr;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001079 }
1080 }
1081
Ben Murdochc5610432016-08-08 18:44:38 +01001082 LocalType GetReturnType(FunctionSig* sig) {
1083 return sig->return_count() == 0 ? kAstStmt : sig->GetReturn();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001084 }
1085
Ben Murdochc5610432016-08-08 18:44:38 +01001086 void PushBlock(SsaEnv* end_env) {
1087 int stack_depth = static_cast<int>(stack_.size());
1088 control_.push_back(
1089 {pc_, stack_depth, end_env, nullptr, nullptr, kAstEnd, false});
1090 }
1091
1092 void PushLoop(SsaEnv* end_env) {
1093 int stack_depth = static_cast<int>(stack_.size());
1094 control_.push_back(
1095 {pc_, stack_depth, end_env, nullptr, nullptr, kAstEnd, true});
1096 }
1097
1098 void PushIf(SsaEnv* end_env, SsaEnv* false_env) {
1099 int stack_depth = static_cast<int>(stack_.size());
1100 control_.push_back(
1101 {pc_, stack_depth, end_env, false_env, nullptr, kAstStmt, false});
1102 }
1103
1104 int DecodeLoadMem(LocalType type, MachineType mem_type) {
1105 MemoryAccessOperand operand(this, pc_);
1106 Value index = Pop(0, kAstI32);
1107 TFNode* node =
1108 BUILD(LoadMem, type, mem_type, index.node, operand.offset, position());
1109 Push(type, node);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001110 return 1 + operand.length;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001111 }
1112
Ben Murdochc5610432016-08-08 18:44:38 +01001113 int DecodeStoreMem(LocalType type, MachineType mem_type) {
1114 MemoryAccessOperand operand(this, pc_);
1115 Value val = Pop(1, type);
1116 Value index = Pop(0, kAstI32);
1117 BUILD(StoreMem, mem_type, index.node, operand.offset, val.node, position());
1118 Push(type, val.node);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001119 return 1 + operand.length;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001120 }
1121
Ben Murdochc5610432016-08-08 18:44:38 +01001122 void DoReturn() {
1123 int count = static_cast<int>(sig_->return_count());
1124 TFNode** buffer = nullptr;
1125 if (build()) buffer = builder_->Buffer(count);
1126
1127 // Pop return values off the stack in reverse order.
1128 for (int i = count - 1; i >= 0; i--) {
1129 Value val = Pop(i, sig_->GetReturn(i));
1130 if (buffer) buffer[i] = val.node;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001131 }
1132
Ben Murdochc5610432016-08-08 18:44:38 +01001133 Push(kAstEnd, BUILD(Return, count, buffer));
1134 ssa_env_->Kill(SsaEnv::kControlEnd);
1135 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001136
Ben Murdochc5610432016-08-08 18:44:38 +01001137 void Push(LocalType type, TFNode* node) {
1138 stack_.push_back({pc_, node, type});
1139 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001140
Ben Murdochc5610432016-08-08 18:44:38 +01001141 const char* SafeOpcodeNameAt(const byte* pc) {
1142 if (pc >= end_) return "<end>";
1143 return WasmOpcodes::ShortOpcodeName(static_cast<WasmOpcode>(*pc));
1144 }
1145
1146 Value Pop(int index, LocalType expected) {
1147 Value val = Pop();
1148 if (val.type != expected) {
1149 if (val.type != kAstEnd) {
1150 error(pc_, val.pc, "%s[%d] expected type %s, found %s of type %s",
1151 SafeOpcodeNameAt(pc_), index, WasmOpcodes::TypeName(expected),
1152 SafeOpcodeNameAt(val.pc), WasmOpcodes::TypeName(val.type));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001153 }
1154 }
Ben Murdochc5610432016-08-08 18:44:38 +01001155 return val;
1156 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001157
Ben Murdochc5610432016-08-08 18:44:38 +01001158 Value Pop() {
1159 size_t limit = control_.empty() ? 0 : control_.back().stack_depth;
1160 if (stack_.size() <= limit) {
1161 Value val = {pc_, nullptr, kAstStmt};
1162 error(pc_, pc_, "%s found empty stack", SafeOpcodeNameAt(pc_));
1163 return val;
1164 }
1165 Value val = stack_.back();
1166 stack_.pop_back();
1167 return val;
1168 }
1169
1170 Value PopUpTo(int stack_depth) {
1171 if (stack_depth == stack_.size()) {
1172 Value val = {pc_, nullptr, kAstStmt};
1173 return val;
1174 } else {
1175 DCHECK_LE(stack_depth, static_cast<int>(stack_.size()));
1176 Value val = Pop();
1177 stack_.resize(stack_depth);
1178 return val;
1179 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001180 }
1181
1182 int baserel(const byte* ptr) {
1183 return base_ ? static_cast<int>(ptr - base_) : 0;
1184 }
1185
1186 int startrel(const byte* ptr) { return static_cast<int>(ptr - start_); }
1187
Ben Murdochc5610432016-08-08 18:44:38 +01001188 void BreakTo(Control* block, Value& val) {
1189 if (block->is_loop) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001190 // This is the inner loop block, which does not have a value.
Ben Murdochc5610432016-08-08 18:44:38 +01001191 Goto(ssa_env_, block->end_env);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001192 } else {
1193 // Merge the value into the production for the block.
Ben Murdochc5610432016-08-08 18:44:38 +01001194 MergeInto(block->end_env, &block->node, &block->type, val);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001195 }
1196 }
1197
Ben Murdochc5610432016-08-08 18:44:38 +01001198 void MergeInto(SsaEnv* target, TFNode** node, LocalType* type, Value& val) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001199 if (!ssa_env_->go()) return;
Ben Murdochc5610432016-08-08 18:44:38 +01001200 DCHECK_NE(kAstEnd, val.type);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001201
1202 bool first = target->state == SsaEnv::kUnreachable;
1203 Goto(ssa_env_, target);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001204
1205 if (first) {
1206 // first merge to this environment; set the type and the node.
Ben Murdochc5610432016-08-08 18:44:38 +01001207 *type = val.type;
1208 *node = val.node;
1209 } else if (val.type == *type && val.type != kAstStmt) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001210 // merge with the existing value for this block.
Ben Murdochc5610432016-08-08 18:44:38 +01001211 *node = CreateOrMergeIntoPhi(*type, target->control, *node, val.node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001212 } else {
Ben Murdochc5610432016-08-08 18:44:38 +01001213 // types don't match, or block is already a stmt.
1214 *type = kAstStmt;
1215 *node = nullptr;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001216 }
1217 }
1218
1219 void SetEnv(const char* reason, SsaEnv* env) {
Ben Murdochda12d292016-06-02 14:46:10 +01001220#if DEBUG
Ben Murdochc5610432016-08-08 18:44:38 +01001221 if (FLAG_trace_wasm_decoder) {
1222 char state = 'X';
1223 if (env) {
1224 switch (env->state) {
1225 case SsaEnv::kReached:
1226 state = 'R';
1227 break;
1228 case SsaEnv::kUnreachable:
1229 state = 'U';
1230 break;
1231 case SsaEnv::kMerged:
1232 state = 'M';
1233 break;
1234 case SsaEnv::kControlEnd:
1235 state = 'E';
1236 break;
1237 }
1238 }
1239 PrintF(" env = %p, state = %c, reason = %s", static_cast<void*>(env),
1240 state, reason);
1241 if (env && env->control) {
1242 PrintF(", control = ");
1243 compiler::WasmGraphBuilder::PrintDebugName(env->control);
1244 }
1245 PrintF("\n");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001246 }
Ben Murdochda12d292016-06-02 14:46:10 +01001247#endif
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001248 ssa_env_ = env;
1249 if (builder_) {
1250 builder_->set_control_ptr(&env->control);
1251 builder_->set_effect_ptr(&env->effect);
1252 }
1253 }
1254
1255 void Goto(SsaEnv* from, SsaEnv* to) {
1256 DCHECK_NOT_NULL(to);
1257 if (!from->go()) return;
1258 switch (to->state) {
1259 case SsaEnv::kUnreachable: { // Overwrite destination.
1260 to->state = SsaEnv::kReached;
1261 to->locals = from->locals;
1262 to->control = from->control;
1263 to->effect = from->effect;
1264 break;
1265 }
1266 case SsaEnv::kReached: { // Create a new merge.
1267 to->state = SsaEnv::kMerged;
1268 if (!builder_) break;
1269 // Merge control.
1270 TFNode* controls[] = {to->control, from->control};
1271 TFNode* merge = builder_->Merge(2, controls);
1272 to->control = merge;
1273 // Merge effects.
1274 if (from->effect != to->effect) {
1275 TFNode* effects[] = {to->effect, from->effect, merge};
1276 to->effect = builder_->EffectPhi(2, effects, merge);
1277 }
1278 // Merge SSA values.
1279 for (int i = EnvironmentCount() - 1; i >= 0; i--) {
1280 TFNode* a = to->locals[i];
1281 TFNode* b = from->locals[i];
1282 if (a != b) {
1283 TFNode* vals[] = {a, b};
Ben Murdochda12d292016-06-02 14:46:10 +01001284 to->locals[i] = builder_->Phi(local_type_vec_[i], 2, vals, merge);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001285 }
1286 }
1287 break;
1288 }
1289 case SsaEnv::kMerged: {
1290 if (!builder_) break;
1291 TFNode* merge = to->control;
1292 // Extend the existing merge.
1293 builder_->AppendToMerge(merge, from->control);
1294 // Merge effects.
1295 if (builder_->IsPhiWithMerge(to->effect, merge)) {
Ben Murdochc5610432016-08-08 18:44:38 +01001296 builder_->AppendToPhi(to->effect, from->effect);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001297 } else if (to->effect != from->effect) {
1298 uint32_t count = builder_->InputCount(merge);
1299 TFNode** effects = builder_->Buffer(count);
1300 for (uint32_t j = 0; j < count - 1; j++) {
1301 effects[j] = to->effect;
1302 }
1303 effects[count - 1] = from->effect;
1304 to->effect = builder_->EffectPhi(count, effects, merge);
1305 }
1306 // Merge locals.
1307 for (int i = EnvironmentCount() - 1; i >= 0; i--) {
1308 TFNode* tnode = to->locals[i];
1309 TFNode* fnode = from->locals[i];
1310 if (builder_->IsPhiWithMerge(tnode, merge)) {
Ben Murdochc5610432016-08-08 18:44:38 +01001311 builder_->AppendToPhi(tnode, fnode);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001312 } else if (tnode != fnode) {
1313 uint32_t count = builder_->InputCount(merge);
1314 TFNode** vals = builder_->Buffer(count);
1315 for (uint32_t j = 0; j < count - 1; j++) {
1316 vals[j] = tnode;
1317 }
1318 vals[count - 1] = fnode;
Ben Murdochda12d292016-06-02 14:46:10 +01001319 to->locals[i] =
1320 builder_->Phi(local_type_vec_[i], count, vals, merge);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001321 }
1322 }
1323 break;
1324 }
1325 default:
1326 UNREACHABLE();
1327 }
1328 return from->Kill();
1329 }
1330
1331 TFNode* CreateOrMergeIntoPhi(LocalType type, TFNode* merge, TFNode* tnode,
1332 TFNode* fnode) {
1333 if (builder_->IsPhiWithMerge(tnode, merge)) {
Ben Murdochc5610432016-08-08 18:44:38 +01001334 builder_->AppendToPhi(tnode, fnode);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001335 } else if (tnode != fnode) {
1336 uint32_t count = builder_->InputCount(merge);
1337 TFNode** vals = builder_->Buffer(count);
1338 for (uint32_t j = 0; j < count - 1; j++) vals[j] = tnode;
1339 vals[count - 1] = fnode;
1340 return builder_->Phi(type, count, vals, merge);
1341 }
1342 return tnode;
1343 }
1344
Ben Murdochda12d292016-06-02 14:46:10 +01001345 void PrepareForLoop(const byte* pc, SsaEnv* env) {
1346 if (!env->go()) return;
1347 env->state = SsaEnv::kMerged;
1348 if (!builder_) return;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001349
Ben Murdochda12d292016-06-02 14:46:10 +01001350 env->control = builder_->Loop(env->control);
1351 env->effect = builder_->EffectPhi(1, &env->effect, env->control);
1352 builder_->Terminate(env->effect, env->control);
1353 if (FLAG_wasm_loop_assignment_analysis) {
1354 BitVector* assigned = AnalyzeLoopAssignment(pc);
1355 if (assigned != nullptr) {
1356 // Only introduce phis for variables assigned in this loop.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001357 for (int i = EnvironmentCount() - 1; i >= 0; i--) {
Ben Murdochda12d292016-06-02 14:46:10 +01001358 if (!assigned->Contains(i)) continue;
1359 env->locals[i] = builder_->Phi(local_type_vec_[i], 1, &env->locals[i],
1360 env->control);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001361 }
Ben Murdochda12d292016-06-02 14:46:10 +01001362 return;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001363 }
1364 }
Ben Murdochda12d292016-06-02 14:46:10 +01001365
1366 // Conservatively introduce phis for all local variables.
1367 for (int i = EnvironmentCount() - 1; i >= 0; i--) {
1368 env->locals[i] =
1369 builder_->Phi(local_type_vec_[i], 1, &env->locals[i], env->control);
1370 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001371 }
1372
1373 // Create a complete copy of the {from}.
1374 SsaEnv* Split(SsaEnv* from) {
1375 DCHECK_NOT_NULL(from);
1376 SsaEnv* result = reinterpret_cast<SsaEnv*>(zone_->New(sizeof(SsaEnv)));
1377 size_t size = sizeof(TFNode*) * EnvironmentCount();
1378 result->control = from->control;
1379 result->effect = from->effect;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001380
1381 if (from->go()) {
1382 result->state = SsaEnv::kReached;
1383 result->locals =
1384 size > 0 ? reinterpret_cast<TFNode**>(zone_->New(size)) : nullptr;
1385 memcpy(result->locals, from->locals, size);
1386 } else {
1387 result->state = SsaEnv::kUnreachable;
1388 result->locals = nullptr;
1389 }
1390
1391 return result;
1392 }
1393
1394 // Create a copy of {from} that steals its state and leaves {from}
1395 // unreachable.
1396 SsaEnv* Steal(SsaEnv* from) {
1397 DCHECK_NOT_NULL(from);
1398 if (!from->go()) return UnreachableEnv();
1399 SsaEnv* result = reinterpret_cast<SsaEnv*>(zone_->New(sizeof(SsaEnv)));
1400 result->state = SsaEnv::kReached;
1401 result->locals = from->locals;
1402 result->control = from->control;
1403 result->effect = from->effect;
1404 from->Kill(SsaEnv::kUnreachable);
1405 return result;
1406 }
1407
1408 // Create an unreachable environment.
1409 SsaEnv* UnreachableEnv() {
1410 SsaEnv* result = reinterpret_cast<SsaEnv*>(zone_->New(sizeof(SsaEnv)));
1411 result->state = SsaEnv::kUnreachable;
1412 result->control = nullptr;
1413 result->effect = nullptr;
1414 result->locals = nullptr;
1415 return result;
1416 }
1417
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001418 int EnvironmentCount() {
Ben Murdochda12d292016-06-02 14:46:10 +01001419 if (builder_) return static_cast<int>(local_type_vec_.size());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001420 return 0; // if we aren't building a graph, don't bother with SSA renaming.
1421 }
1422
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001423 virtual void onFirstError() {
1424 limit_ = start_; // Terminate decoding loop.
1425 builder_ = nullptr; // Don't build any more nodes.
Ben Murdochc5610432016-08-08 18:44:38 +01001426 TRACE(" !%s\n", error_msg_.get());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001427 }
Ben Murdochda12d292016-06-02 14:46:10 +01001428 BitVector* AnalyzeLoopAssignment(const byte* pc) {
1429 if (pc >= limit_) return nullptr;
1430 if (*pc != kExprLoop) return nullptr;
1431
1432 BitVector* assigned =
Ben Murdochc5610432016-08-08 18:44:38 +01001433 new (zone_) BitVector(static_cast<int>(local_type_vec_.size()), zone_);
1434 int depth = 0;
Ben Murdochda12d292016-06-02 14:46:10 +01001435 // Iteratively process all AST nodes nested inside the loop.
1436 while (pc < limit_) {
1437 WasmOpcode opcode = static_cast<WasmOpcode>(*pc);
Ben Murdochda12d292016-06-02 14:46:10 +01001438 int length = 1;
Ben Murdochc5610432016-08-08 18:44:38 +01001439 switch (opcode) {
1440 case kExprLoop:
1441 case kExprIf:
1442 case kExprBlock:
1443 depth++;
1444 DCHECK_EQ(1, OpcodeLength(pc));
1445 break;
1446 case kExprSetLocal: {
1447 LocalIndexOperand operand(this, pc);
1448 if (assigned->length() > 0 &&
1449 static_cast<int>(operand.index) < assigned->length()) {
1450 // Unverified code might have an out-of-bounds index.
1451 assigned->Add(operand.index);
1452 }
1453 length = 1 + operand.length;
1454 break;
Ben Murdochda12d292016-06-02 14:46:10 +01001455 }
Ben Murdochc5610432016-08-08 18:44:38 +01001456 case kExprEnd:
1457 depth--;
1458 break;
1459 default:
1460 length = OpcodeLength(pc);
1461 break;
Ben Murdochda12d292016-06-02 14:46:10 +01001462 }
Ben Murdochc5610432016-08-08 18:44:38 +01001463 if (depth <= 0) break;
Ben Murdochda12d292016-06-02 14:46:10 +01001464 pc += length;
Ben Murdochda12d292016-06-02 14:46:10 +01001465 }
1466 return assigned;
1467 }
Ben Murdochc5610432016-08-08 18:44:38 +01001468
1469 inline wasm::WasmCodePosition position() {
1470 int offset = static_cast<int>(pc_ - start_);
1471 DCHECK_EQ(pc_ - start_, offset); // overflows cannot happen
1472 return offset;
1473 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001474};
1475
Ben Murdochda12d292016-06-02 14:46:10 +01001476bool DecodeLocalDecls(AstLocalDecls& decls, const byte* start,
1477 const byte* end) {
1478 base::AccountingAllocator allocator;
1479 Zone tmp(&allocator);
1480 FunctionBody body = {nullptr, nullptr, nullptr, start, end};
1481 SR_WasmDecoder decoder(&tmp, nullptr, body);
1482 return decoder.DecodeLocalDecls(decls);
1483}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001484
Ben Murdochda12d292016-06-02 14:46:10 +01001485TreeResult VerifyWasmCode(base::AccountingAllocator* allocator,
1486 FunctionBody& body) {
1487 Zone zone(allocator);
1488 SR_WasmDecoder decoder(&zone, nullptr, body);
Ben Murdochc5610432016-08-08 18:44:38 +01001489 decoder.Decode();
1490 return decoder.toResult<Tree*>(nullptr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001491}
1492
Ben Murdochda12d292016-06-02 14:46:10 +01001493TreeResult BuildTFGraph(base::AccountingAllocator* allocator,
1494 TFBuilder* builder, FunctionBody& body) {
1495 Zone zone(allocator);
1496 SR_WasmDecoder decoder(&zone, builder, body);
Ben Murdochc5610432016-08-08 18:44:38 +01001497 decoder.Decode();
1498 return decoder.toResult<Tree*>(nullptr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001499}
1500
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001501std::ostream& operator<<(std::ostream& os, const Tree& tree) {
1502 if (tree.pc == nullptr) {
1503 os << "null";
1504 return os;
1505 }
1506 PrintF("%s", WasmOpcodes::OpcodeName(tree.opcode()));
1507 if (tree.count > 0) os << "(";
1508 for (uint32_t i = 0; i < tree.count; i++) {
1509 if (i > 0) os << ", ";
1510 os << *tree.children[i];
1511 }
1512 if (tree.count > 0) os << ")";
1513 return os;
1514}
1515
Ben Murdoch097c5b22016-05-18 11:27:45 +01001516int OpcodeLength(const byte* pc, const byte* end) {
Ben Murdochda12d292016-06-02 14:46:10 +01001517 WasmDecoder decoder(nullptr, nullptr, pc, end);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001518 return decoder.OpcodeLength(pc);
1519}
1520
Ben Murdochc5610432016-08-08 18:44:38 +01001521int OpcodeArity(const byte* pc, const byte* end) {
1522 WasmDecoder decoder(nullptr, nullptr, pc, end);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001523 return decoder.OpcodeArity(pc);
1524}
1525
Ben Murdochc5610432016-08-08 18:44:38 +01001526void PrintAstForDebugging(const byte* start, const byte* end) {
1527 FunctionBody body = {nullptr, nullptr, start, start, end};
1528 base::AccountingAllocator allocator;
1529 PrintAst(&allocator, body);
1530}
1531
Ben Murdochda12d292016-06-02 14:46:10 +01001532void PrintAst(base::AccountingAllocator* allocator, FunctionBody& body) {
1533 Zone zone(allocator);
1534 SR_WasmDecoder decoder(&zone, nullptr, body);
1535
1536 OFStream os(stdout);
1537
1538 // Print the function signature.
1539 if (body.sig) {
1540 os << "// signature: " << *body.sig << std::endl;
1541 }
1542
1543 // Print the local declarations.
1544 AstLocalDecls decls(&zone);
1545 decoder.DecodeLocalDecls(decls);
1546 const byte* pc = decoder.pc();
1547 if (body.start != decoder.pc()) {
Ben Murdochc5610432016-08-08 18:44:38 +01001548 os << "// locals: ";
Ben Murdochda12d292016-06-02 14:46:10 +01001549 for (auto p : decls.local_types) {
1550 LocalType type = p.first;
1551 uint32_t count = p.second;
1552 os << " " << count << " " << WasmOpcodes::TypeName(type);
1553 }
1554 os << std::endl;
1555
1556 for (const byte* locals = body.start; locals < pc; locals++) {
1557 printf(" 0x%02x,", *locals);
1558 }
Ben Murdochc5610432016-08-08 18:44:38 +01001559 os << std::endl;
Ben Murdochda12d292016-06-02 14:46:10 +01001560 }
1561
Ben Murdochc5610432016-08-08 18:44:38 +01001562 os << "// body: \n";
1563 int control_depth = 0;
Ben Murdochda12d292016-06-02 14:46:10 +01001564 while (pc < body.end) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001565 size_t length = decoder.OpcodeLength(pc);
1566
Ben Murdoch097c5b22016-05-18 11:27:45 +01001567 WasmOpcode opcode = static_cast<WasmOpcode>(*pc);
Ben Murdochc5610432016-08-08 18:44:38 +01001568 if (opcode == kExprElse) control_depth--;
1569
1570 for (int i = 0; i < control_depth && i < 32; i++) printf(" ");
Ben Murdoch097c5b22016-05-18 11:27:45 +01001571 printf("k%s,", WasmOpcodes::OpcodeName(opcode));
1572
1573 for (size_t i = 1; i < length; i++) {
1574 printf(" 0x%02x,", pc[i]);
1575 }
Ben Murdochda12d292016-06-02 14:46:10 +01001576
Ben Murdochc5610432016-08-08 18:44:38 +01001577 switch (opcode) {
1578 case kExprIf:
1579 case kExprElse:
1580 case kExprLoop:
1581 case kExprBlock:
1582 os << " // @" << static_cast<int>(pc - body.start);
1583 control_depth++;
1584 break;
1585 case kExprEnd:
1586 os << " // @" << static_cast<int>(pc - body.start);
1587 control_depth--;
1588 break;
1589 case kExprBr: {
1590 BreakDepthOperand operand(&decoder, pc);
1591 os << " // arity=" << operand.arity << " depth=" << operand.depth;
1592 break;
Ben Murdochda12d292016-06-02 14:46:10 +01001593 }
Ben Murdochc5610432016-08-08 18:44:38 +01001594 case kExprBrIf: {
1595 BreakDepthOperand operand(&decoder, pc);
1596 os << " // arity=" << operand.arity << " depth" << operand.depth;
1597 break;
1598 }
1599 case kExprBrTable: {
1600 BranchTableOperand operand(&decoder, pc);
1601 os << " // arity=" << operand.arity
1602 << " entries=" << operand.table_count;
1603 break;
1604 }
1605 case kExprCallIndirect: {
1606 CallIndirectOperand operand(&decoder, pc);
1607 if (decoder.Validate(pc, operand)) {
1608 os << " // sig #" << operand.index << ": " << *operand.sig;
1609 } else {
1610 os << " // arity=" << operand.arity << " sig #" << operand.index;
1611 }
1612 break;
1613 }
1614 case kExprCallImport: {
1615 CallImportOperand operand(&decoder, pc);
1616 if (decoder.Validate(pc, operand)) {
1617 os << " // import #" << operand.index << ": " << *operand.sig;
1618 } else {
1619 os << " // arity=" << operand.arity << " import #" << operand.index;
1620 }
1621 break;
1622 }
1623 case kExprCallFunction: {
1624 CallFunctionOperand operand(&decoder, pc);
1625 if (decoder.Validate(pc, operand)) {
1626 os << " // function #" << operand.index << ": " << *operand.sig;
1627 } else {
1628 os << " // arity=" << operand.arity << " function #" << operand.index;
1629 }
1630 break;
1631 }
1632 case kExprReturn: {
1633 ReturnArityOperand operand(&decoder, pc);
1634 os << " // arity=" << operand.arity;
1635 break;
1636 }
1637 default:
1638 break;
1639 }
Ben Murdochda12d292016-06-02 14:46:10 +01001640
Ben Murdoch097c5b22016-05-18 11:27:45 +01001641 pc += length;
Ben Murdochc5610432016-08-08 18:44:38 +01001642 os << std::endl;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001643 }
1644}
1645
Ben Murdochda12d292016-06-02 14:46:10 +01001646BitVector* AnalyzeLoopAssignmentForTesting(Zone* zone, size_t num_locals,
Ben Murdoch097c5b22016-05-18 11:27:45 +01001647 const byte* start, const byte* end) {
Ben Murdochda12d292016-06-02 14:46:10 +01001648 FunctionBody body = {nullptr, nullptr, nullptr, start, end};
1649 SR_WasmDecoder decoder(zone, nullptr, body);
1650 return decoder.AnalyzeLoopAssignmentForTesting(start, num_locals);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001651}
1652
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001653} // namespace wasm
1654} // namespace internal
1655} // namespace v8