blob: ef83c6774d4e0c36f197d08bacdae31a80b04eb9 [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 Murdoch61f157c2016-09-16 13:49:30 +0100160 inline bool Complete(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 Murdoch61f157c2016-09-16 13:49:30 +0100164 return true;
165 }
166 return false;
167 }
168
169 inline bool Validate(const byte* pc, CallFunctionOperand& operand) {
170 if (Complete(pc, operand)) {
Ben Murdochc5610432016-08-08 18:44:38 +0100171 uint32_t expected = static_cast<uint32_t>(operand.sig->parameter_count());
172 if (operand.arity != expected) {
173 error(pc, pc + 1,
174 "arity mismatch in direct function call (expected %u, got %u)",
175 expected, operand.arity);
176 return false;
177 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100178 return true;
179 }
180 error(pc, pc + 1, "invalid function index");
181 return false;
182 }
183
Ben Murdoch61f157c2016-09-16 13:49:30 +0100184 inline bool Complete(const byte* pc, CallIndirectOperand& operand) {
Ben Murdochda12d292016-06-02 14:46:10 +0100185 ModuleEnv* m = module_;
186 if (m && m->module && operand.index < m->module->signatures.size()) {
187 operand.sig = m->module->signatures[operand.index];
Ben Murdoch61f157c2016-09-16 13:49:30 +0100188 return true;
189 }
190 return false;
191 }
192
193 inline bool Validate(const byte* pc, CallIndirectOperand& operand) {
194 if (Complete(pc, operand)) {
Ben Murdochc5610432016-08-08 18:44:38 +0100195 uint32_t expected = static_cast<uint32_t>(operand.sig->parameter_count());
196 if (operand.arity != expected) {
197 error(pc, pc + 1,
198 "arity mismatch in indirect function call (expected %u, got %u)",
199 expected, operand.arity);
200 return false;
201 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100202 return true;
203 }
204 error(pc, pc + 1, "invalid signature index");
205 return false;
206 }
207
Ben Murdoch61f157c2016-09-16 13:49:30 +0100208 inline bool Complete(const byte* pc, CallImportOperand& operand) {
Ben Murdochda12d292016-06-02 14:46:10 +0100209 ModuleEnv* m = module_;
210 if (m && m->module && operand.index < m->module->import_table.size()) {
211 operand.sig = m->module->import_table[operand.index].sig;
Ben Murdoch61f157c2016-09-16 13:49:30 +0100212 return true;
213 }
214 return false;
215 }
216
217 inline bool Validate(const byte* pc, CallImportOperand& operand) {
218 if (Complete(pc, operand)) {
Ben Murdochc5610432016-08-08 18:44:38 +0100219 uint32_t expected = static_cast<uint32_t>(operand.sig->parameter_count());
220 if (operand.arity != expected) {
221 error(pc, pc + 1, "arity mismatch in import call (expected %u, got %u)",
222 expected, operand.arity);
223 return false;
224 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100225 return true;
226 }
227 error(pc, pc + 1, "invalid signature index");
228 return false;
229 }
230
231 inline bool Validate(const byte* pc, BreakDepthOperand& operand,
Ben Murdochc5610432016-08-08 18:44:38 +0100232 ZoneVector<Control>& control) {
233 if (operand.arity > 1) {
234 error(pc, pc + 1, "invalid arity for br or br_if");
235 return false;
236 }
237 if (operand.depth < control.size()) {
238 operand.target = &control[control.size() - operand.depth - 1];
Ben Murdoch097c5b22016-05-18 11:27:45 +0100239 return true;
240 }
241 error(pc, pc + 1, "invalid break depth");
242 return false;
243 }
244
Ben Murdochda12d292016-06-02 14:46:10 +0100245 bool Validate(const byte* pc, BranchTableOperand& operand,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100246 size_t block_depth) {
Ben Murdochc5610432016-08-08 18:44:38 +0100247 if (operand.arity > 1) {
248 error(pc, pc + 1, "invalid arity for break");
249 return false;
250 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100251 // Verify table.
Ben Murdoch61f157c2016-09-16 13:49:30 +0100252 for (uint32_t i = 0; i < operand.table_count + 1; ++i) {
Ben Murdochda12d292016-06-02 14:46:10 +0100253 uint32_t target = operand.read_entry(this, i);
254 if (target >= block_depth) {
255 error(operand.table + i * 2, "improper branch in br_table");
256 return false;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100257 }
258 }
259 return true;
260 }
261
Ben Murdoch61f157c2016-09-16 13:49:30 +0100262 unsigned OpcodeArity(const byte* pc) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100263#define DECLARE_ARITY(name, ...) \
264 static const LocalType kTypes_##name[] = {__VA_ARGS__}; \
265 static const int kArity_##name = \
266 static_cast<int>(arraysize(kTypes_##name) - 1);
267
268 FOREACH_SIGNATURE(DECLARE_ARITY);
269#undef DECLARE_ARITY
270
271 switch (static_cast<WasmOpcode>(*pc)) {
272 case kExprI8Const:
273 case kExprI32Const:
274 case kExprI64Const:
275 case kExprF64Const:
276 case kExprF32Const:
277 case kExprGetLocal:
278 case kExprLoadGlobal:
279 case kExprNop:
280 case kExprUnreachable:
Ben Murdochc5610432016-08-08 18:44:38 +0100281 case kExprEnd:
282 case kExprBlock:
283 case kExprLoop:
Ben Murdoch097c5b22016-05-18 11:27:45 +0100284 return 0;
285
Ben Murdoch097c5b22016-05-18 11:27:45 +0100286 case kExprStoreGlobal:
287 case kExprSetLocal:
Ben Murdochc5610432016-08-08 18:44:38 +0100288 case kExprElse:
Ben Murdoch097c5b22016-05-18 11:27:45 +0100289 return 1;
290
Ben Murdochc5610432016-08-08 18:44:38 +0100291 case kExprBr: {
292 BreakDepthOperand operand(this, pc);
293 return operand.arity;
294 }
295 case kExprBrIf: {
296 BreakDepthOperand operand(this, pc);
297 return 1 + operand.arity;
298 }
299 case kExprBrTable: {
300 BranchTableOperand operand(this, pc);
301 return 1 + operand.arity;
302 }
303
Ben Murdoch097c5b22016-05-18 11:27:45 +0100304 case kExprIf:
Ben Murdochc5610432016-08-08 18:44:38 +0100305 return 1;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100306 case kExprSelect:
307 return 3;
308
Ben Murdoch097c5b22016-05-18 11:27:45 +0100309 case kExprCallFunction: {
Ben Murdochc5610432016-08-08 18:44:38 +0100310 CallFunctionOperand operand(this, pc);
311 return operand.arity;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100312 }
313 case kExprCallIndirect: {
Ben Murdochc5610432016-08-08 18:44:38 +0100314 CallIndirectOperand operand(this, pc);
315 return 1 + operand.arity;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100316 }
317 case kExprCallImport: {
Ben Murdochc5610432016-08-08 18:44:38 +0100318 CallImportOperand operand(this, pc);
319 return operand.arity;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100320 }
321 case kExprReturn: {
Ben Murdochc5610432016-08-08 18:44:38 +0100322 ReturnArityOperand operand(this, pc);
323 return operand.arity;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100324 }
325
326#define DECLARE_OPCODE_CASE(name, opcode, sig) \
327 case kExpr##name: \
328 return kArity_##sig;
329
330 FOREACH_LOAD_MEM_OPCODE(DECLARE_OPCODE_CASE)
331 FOREACH_STORE_MEM_OPCODE(DECLARE_OPCODE_CASE)
332 FOREACH_MISC_MEM_OPCODE(DECLARE_OPCODE_CASE)
333 FOREACH_SIMPLE_OPCODE(DECLARE_OPCODE_CASE)
Ben Murdochda12d292016-06-02 14:46:10 +0100334 FOREACH_ASMJS_COMPAT_OPCODE(DECLARE_OPCODE_CASE)
Ben Murdoch61f157c2016-09-16 13:49:30 +0100335 FOREACH_SIMD_OPCODE(DECLARE_OPCODE_CASE)
Ben Murdoch097c5b22016-05-18 11:27:45 +0100336#undef DECLARE_OPCODE_CASE
Ben Murdochda12d292016-06-02 14:46:10 +0100337 default:
338 UNREACHABLE();
339 return 0;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100340 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100341 }
342
Ben Murdoch61f157c2016-09-16 13:49:30 +0100343 unsigned OpcodeLength(const byte* pc) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100344 switch (static_cast<WasmOpcode>(*pc)) {
345#define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name:
346 FOREACH_LOAD_MEM_OPCODE(DECLARE_OPCODE_CASE)
347 FOREACH_STORE_MEM_OPCODE(DECLARE_OPCODE_CASE)
348#undef DECLARE_OPCODE_CASE
349 {
350 MemoryAccessOperand operand(this, pc);
351 return 1 + operand.length;
352 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100353 case kExprBr:
354 case kExprBrIf: {
355 BreakDepthOperand operand(this, pc);
356 return 1 + operand.length;
357 }
358 case kExprStoreGlobal:
359 case kExprLoadGlobal: {
360 GlobalIndexOperand operand(this, pc);
361 return 1 + operand.length;
362 }
363
364 case kExprCallFunction: {
Ben Murdochc5610432016-08-08 18:44:38 +0100365 CallFunctionOperand operand(this, pc);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100366 return 1 + operand.length;
367 }
368 case kExprCallIndirect: {
Ben Murdochc5610432016-08-08 18:44:38 +0100369 CallIndirectOperand operand(this, pc);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100370 return 1 + operand.length;
371 }
372 case kExprCallImport: {
Ben Murdochc5610432016-08-08 18:44:38 +0100373 CallImportOperand operand(this, pc);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100374 return 1 + operand.length;
375 }
376
377 case kExprSetLocal:
378 case kExprGetLocal: {
379 LocalIndexOperand operand(this, pc);
380 return 1 + operand.length;
381 }
Ben Murdochda12d292016-06-02 14:46:10 +0100382 case kExprBrTable: {
383 BranchTableOperand operand(this, pc);
384 return 1 + operand.length;
385 }
386 case kExprI32Const: {
387 ImmI32Operand operand(this, pc);
388 return 1 + operand.length;
389 }
390 case kExprI64Const: {
391 ImmI64Operand operand(this, pc);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100392 return 1 + operand.length;
393 }
394 case kExprI8Const:
395 return 2;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100396 case kExprF32Const:
397 return 5;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100398 case kExprF64Const:
399 return 9;
Ben Murdochc5610432016-08-08 18:44:38 +0100400 case kExprReturn: {
401 ReturnArityOperand operand(this, pc);
402 return 1 + operand.length;
403 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100404
405 default:
406 return 1;
407 }
408 }
409};
410
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000411// A shift-reduce-parser strategy for decoding Wasm code that uses an explicit
412// shift-reduce strategy with multiple internal stacks.
Ben Murdochda12d292016-06-02 14:46:10 +0100413class SR_WasmDecoder : public WasmDecoder {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000414 public:
Ben Murdoch61f157c2016-09-16 13:49:30 +0100415 SR_WasmDecoder(Zone* zone, TFBuilder* builder, const FunctionBody& body)
Ben Murdochda12d292016-06-02 14:46:10 +0100416 : WasmDecoder(body.module, body.sig, body.start, body.end),
417 zone_(zone),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000418 builder_(builder),
Ben Murdochda12d292016-06-02 14:46:10 +0100419 base_(body.base),
420 local_type_vec_(zone),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000421 stack_(zone),
Ben Murdochc5610432016-08-08 18:44:38 +0100422 control_(zone) {
Ben Murdochda12d292016-06-02 14:46:10 +0100423 local_types_ = &local_type_vec_;
424 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000425
Ben Murdochc5610432016-08-08 18:44:38 +0100426 bool Decode() {
427 base::ElapsedTimer decode_timer;
428 if (FLAG_trace_wasm_decode_time) {
429 decode_timer.Start();
430 }
431 stack_.clear();
432 control_.clear();
433
Ben Murdochda12d292016-06-02 14:46:10 +0100434 if (end_ < pc_) {
435 error(pc_, "function body end < start");
Ben Murdochc5610432016-08-08 18:44:38 +0100436 return false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000437 }
438
Ben Murdochda12d292016-06-02 14:46:10 +0100439 DecodeLocalDecls();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000440 InitSsaEnv();
441 DecodeFunctionBody();
442
Ben Murdochc5610432016-08-08 18:44:38 +0100443 if (failed()) return TraceFailed();
444
445 if (!control_.empty()) {
446 error(pc_, control_.back().pc, "unterminated control structure");
447 return TraceFailed();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000448 }
449
Ben Murdochc5610432016-08-08 18:44:38 +0100450 if (ssa_env_->go()) {
451 TRACE(" @%-6d #xx:%-20s|", startrel(pc_), "ImplicitReturn");
452 DoReturn();
453 if (failed()) return TraceFailed();
454 TRACE("\n");
455 }
456
457 if (FLAG_trace_wasm_decode_time) {
458 double ms = decode_timer.Elapsed().InMillisecondsF();
459 PrintF("wasm-decode ok (%0.3f ms)\n\n", ms);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000460 } else {
Ben Murdochc5610432016-08-08 18:44:38 +0100461 TRACE("wasm-decode ok\n\n");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000462 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100463
Ben Murdochc5610432016-08-08 18:44:38 +0100464 return true;
465 }
466
467 bool TraceFailed() {
468 TRACE("wasm-error module+%-6d func+%d: %s\n\n", baserel(error_pc_),
469 startrel(error_pc_), error_msg_.get());
470 return false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000471 }
472
Ben Murdochda12d292016-06-02 14:46:10 +0100473 bool DecodeLocalDecls(AstLocalDecls& decls) {
474 DecodeLocalDecls();
475 if (failed()) return false;
476 decls.decls_encoded_size = pc_offset();
Ben Murdochda12d292016-06-02 14:46:10 +0100477 decls.local_types.reserve(local_type_vec_.size());
478 for (size_t pos = 0; pos < local_type_vec_.size();) {
479 uint32_t count = 0;
480 LocalType type = local_type_vec_[pos];
481 while (pos < local_type_vec_.size() && local_type_vec_[pos] == type) {
482 pos++;
483 count++;
484 }
Ben Murdochda12d292016-06-02 14:46:10 +0100485 decls.local_types.push_back(std::pair<LocalType, uint32_t>(type, count));
486 }
Ben Murdochc5610432016-08-08 18:44:38 +0100487 decls.total_local_count = static_cast<uint32_t>(local_type_vec_.size());
Ben Murdochda12d292016-06-02 14:46:10 +0100488 return true;
489 }
490
491 BitVector* AnalyzeLoopAssignmentForTesting(const byte* pc,
492 size_t num_locals) {
493 total_locals_ = num_locals;
494 local_type_vec_.reserve(num_locals);
495 if (num_locals > local_type_vec_.size()) {
496 local_type_vec_.insert(local_type_vec_.end(),
497 num_locals - local_type_vec_.size(), kAstI32);
498 }
499 return AnalyzeLoopAssignment(pc);
500 }
501
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000502 private:
503 static const size_t kErrorMsgSize = 128;
504
505 Zone* zone_;
506 TFBuilder* builder_;
507 const byte* base_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000508
509 SsaEnv* ssa_env_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000510
Ben Murdochc5610432016-08-08 18:44:38 +0100511 ZoneVector<LocalType> local_type_vec_; // types of local variables.
512 ZoneVector<Value> stack_; // stack of values.
513 ZoneVector<Control> control_; // stack of blocks, loops, and ifs.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000514
515 inline bool build() { return builder_ && ssa_env_->go(); }
516
517 void InitSsaEnv() {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000518 TFNode* start = nullptr;
519 SsaEnv* ssa_env = reinterpret_cast<SsaEnv*>(zone_->New(sizeof(SsaEnv)));
520 size_t size = sizeof(TFNode*) * EnvironmentCount();
521 ssa_env->state = SsaEnv::kReached;
522 ssa_env->locals =
523 size > 0 ? reinterpret_cast<TFNode**>(zone_->New(size)) : nullptr;
524
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000525 if (builder_) {
Ben Murdochda12d292016-06-02 14:46:10 +0100526 start = builder_->Start(static_cast<int>(sig_->parameter_count() + 1));
527 // Initialize local variables.
528 uint32_t index = 0;
529 while (index < sig_->parameter_count()) {
530 ssa_env->locals[index] = builder_->Param(index, local_type_vec_[index]);
531 index++;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000532 }
Ben Murdochda12d292016-06-02 14:46:10 +0100533 while (index < local_type_vec_.size()) {
534 LocalType type = local_type_vec_[index];
535 TFNode* node = DefaultValue(type);
536 while (index < local_type_vec_.size() &&
537 local_type_vec_[index] == type) {
538 // Do a whole run of like-typed locals at a time.
539 ssa_env->locals[index++] = node;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000540 }
541 }
Ben Murdochda12d292016-06-02 14:46:10 +0100542 builder_->set_module(module_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000543 }
544 ssa_env->control = start;
545 ssa_env->effect = start;
546 SetEnv("initial", ssa_env);
547 }
548
Ben Murdochda12d292016-06-02 14:46:10 +0100549 TFNode* DefaultValue(LocalType type) {
550 switch (type) {
551 case kAstI32:
552 return builder_->Int32Constant(0);
553 case kAstI64:
554 return builder_->Int64Constant(0);
555 case kAstF32:
556 return builder_->Float32Constant(0);
557 case kAstF64:
558 return builder_->Float64Constant(0);
559 default:
560 UNREACHABLE();
561 return nullptr;
562 }
563 }
564
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000565 char* indentation() {
566 static const int kMaxIndent = 64;
567 static char bytes[kMaxIndent + 1];
Ben Murdoch61f157c2016-09-16 13:49:30 +0100568 for (int i = 0; i < kMaxIndent; ++i) bytes[i] = ' ';
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000569 bytes[kMaxIndent] = 0;
570 if (stack_.size() < kMaxIndent / 2) {
571 bytes[stack_.size() * 2] = 0;
572 }
573 return bytes;
574 }
575
Ben Murdochda12d292016-06-02 14:46:10 +0100576 // Decodes the locals declarations, if any, populating {local_type_vec_}.
577 void DecodeLocalDecls() {
578 DCHECK_EQ(0, local_type_vec_.size());
579 // Initialize {local_type_vec} from signature.
580 if (sig_) {
581 local_type_vec_.reserve(sig_->parameter_count());
Ben Murdoch61f157c2016-09-16 13:49:30 +0100582 for (size_t i = 0; i < sig_->parameter_count(); ++i) {
Ben Murdochda12d292016-06-02 14:46:10 +0100583 local_type_vec_.push_back(sig_->GetParam(i));
584 }
585 }
586 // Decode local declarations, if any.
Ben Murdoch61f157c2016-09-16 13:49:30 +0100587 uint32_t entries = consume_u32v("local decls count");
Ben Murdochda12d292016-06-02 14:46:10 +0100588 while (entries-- > 0 && pc_ < limit_) {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100589 uint32_t count = consume_u32v("local count");
Ben Murdochda12d292016-06-02 14:46:10 +0100590 byte code = consume_u8("local type");
591 LocalType type;
592 switch (code) {
593 case kLocalI32:
594 type = kAstI32;
595 break;
596 case kLocalI64:
597 type = kAstI64;
598 break;
599 case kLocalF32:
600 type = kAstF32;
601 break;
602 case kLocalF64:
603 type = kAstF64;
604 break;
605 default:
606 error(pc_ - 1, "invalid local type");
607 return;
608 }
609 local_type_vec_.insert(local_type_vec_.end(), count, type);
610 }
611 total_locals_ = local_type_vec_.size();
612 }
613
Ben Murdochc5610432016-08-08 18:44:38 +0100614 // Decodes the body of a function.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000615 void DecodeFunctionBody() {
Ben Murdochc5610432016-08-08 18:44:38 +0100616 TRACE("wasm-decode %p...%p (module+%d, %d bytes) %s\n",
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000617 reinterpret_cast<const void*>(start_),
Ben Murdochc5610432016-08-08 18:44:38 +0100618 reinterpret_cast<const void*>(limit_), baserel(pc_),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000619 static_cast<int>(limit_ - start_), builder_ ? "graph building" : "");
620
621 if (pc_ >= limit_) return; // Nothing to do.
622
623 while (true) { // decoding loop.
Ben Murdoch61f157c2016-09-16 13:49:30 +0100624 unsigned len = 1;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000625 WasmOpcode opcode = static_cast<WasmOpcode>(*pc_);
Ben Murdochc5610432016-08-08 18:44:38 +0100626 TRACE(" @%-6d #%02x:%-20s|", startrel(pc_), opcode,
627 WasmOpcodes::ShortOpcodeName(opcode));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000628
629 FunctionSig* sig = WasmOpcodes::Signature(opcode);
630 if (sig) {
Ben Murdochc5610432016-08-08 18:44:38 +0100631 // Fast case of a simple operator.
632 TFNode* node;
633 switch (sig->parameter_count()) {
634 case 1: {
635 Value val = Pop(0, sig->GetParam(0));
636 node = BUILD(Unop, opcode, val.node, position());
637 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000638 }
Ben Murdochc5610432016-08-08 18:44:38 +0100639 case 2: {
640 Value rval = Pop(1, sig->GetParam(1));
641 Value lval = Pop(0, sig->GetParam(0));
642 node = BUILD(Binop, opcode, lval.node, rval.node, position());
643 break;
644 }
645 default:
646 UNREACHABLE();
647 node = nullptr;
648 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000649 }
Ben Murdochc5610432016-08-08 18:44:38 +0100650 Push(GetReturnType(sig), node);
651 } else {
652 // Complex bytecode.
653 switch (opcode) {
654 case kExprNop:
655 Push(kAstStmt, nullptr);
656 break;
657 case kExprBlock: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000658 // The break environment is the outer environment.
659 SsaEnv* break_env = ssa_env_;
660 PushBlock(break_env);
661 SetEnv("block:start", Steal(break_env));
Ben Murdochc5610432016-08-08 18:44:38 +0100662 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000663 }
Ben Murdochc5610432016-08-08 18:44:38 +0100664 case kExprLoop: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000665 // The break environment is the outer environment.
666 SsaEnv* break_env = ssa_env_;
667 PushBlock(break_env);
668 SsaEnv* cont_env = Steal(break_env);
669 // The continue environment is the inner environment.
Ben Murdochda12d292016-06-02 14:46:10 +0100670 PrepareForLoop(pc_, cont_env);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000671 SetEnv("loop:start", Split(cont_env));
Ben Murdochc5610432016-08-08 18:44:38 +0100672 ssa_env_->SetNotMerged();
673 PushLoop(cont_env);
674 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000675 }
Ben Murdochc5610432016-08-08 18:44:38 +0100676 case kExprIf: {
677 // Condition on top of stack. Split environments for branches.
678 Value cond = Pop(0, kAstI32);
679 TFNode* if_true = nullptr;
680 TFNode* if_false = nullptr;
681 BUILD(Branch, cond.node, &if_true, &if_false);
682 SsaEnv* end_env = ssa_env_;
683 SsaEnv* false_env = Split(ssa_env_);
684 false_env->control = if_false;
685 SsaEnv* true_env = Steal(ssa_env_);
686 true_env->control = if_true;
687 PushIf(end_env, false_env);
688 SetEnv("if:true", true_env);
689 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000690 }
Ben Murdochc5610432016-08-08 18:44:38 +0100691 case kExprElse: {
692 if (control_.empty()) {
693 error(pc_, "else does not match any if");
694 break;
695 }
696 Control* c = &control_.back();
697 if (!c->is_if()) {
698 error(pc_, c->pc, "else does not match an if");
699 break;
700 }
701 if (c->false_env == nullptr) {
702 error(pc_, c->pc, "else already present for if");
703 break;
704 }
705 Value val = PopUpTo(c->stack_depth);
706 MergeInto(c->end_env, &c->node, &c->type, val);
707 // Switch to environment for false branch.
708 SetEnv("if_else:false", c->false_env);
709 c->false_env = nullptr; // record that an else is already seen
710 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000711 }
Ben Murdochc5610432016-08-08 18:44:38 +0100712 case kExprEnd: {
713 if (control_.empty()) {
714 error(pc_, "end does not match any if or block");
715 break;
716 }
717 const char* name = "block:end";
718 Control* c = &control_.back();
719 if (c->is_loop) {
720 // Loops always push control in pairs.
721 control_.pop_back();
722 c = &control_.back();
723 name = "loop:end";
724 }
725 Value val = PopUpTo(c->stack_depth);
726 if (c->is_if()) {
727 if (c->false_env != nullptr) {
728 // End the true branch of a one-armed if.
729 Goto(c->false_env, c->end_env);
730 val = {val.pc, nullptr, kAstStmt};
731 name = "if:merge";
732 } else {
733 // End the false branch of a two-armed if.
734 name = "if_else:merge";
735 }
736 }
737 if (ssa_env_->go()) {
738 MergeInto(c->end_env, &c->node, &c->type, val);
739 }
740 SetEnv(name, c->end_env);
741 stack_.resize(c->stack_depth);
742 Push(c->type, c->node);
743 control_.pop_back();
744 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000745 }
Ben Murdochc5610432016-08-08 18:44:38 +0100746 case kExprSelect: {
747 Value cond = Pop(2, kAstI32);
748 Value fval = Pop();
749 Value tval = Pop();
750 if (tval.type == kAstStmt || tval.type != fval.type) {
751 if (tval.type != kAstEnd && fval.type != kAstEnd) {
752 error(pc_, "type mismatch in select");
753 break;
754 }
755 }
756 if (build()) {
757 DCHECK(tval.type != kAstEnd);
758 DCHECK(fval.type != kAstEnd);
759 DCHECK(cond.type != kAstEnd);
760 TFNode* controls[2];
761 builder_->Branch(cond.node, &controls[0], &controls[1]);
762 TFNode* merge = builder_->Merge(2, controls);
763 TFNode* vals[2] = {tval.node, fval.node};
764 TFNode* phi = builder_->Phi(tval.type, 2, vals, merge);
765 Push(tval.type, phi);
766 ssa_env_->control = merge;
767 } else {
768 Push(tval.type, nullptr);
769 }
770 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000771 }
Ben Murdochc5610432016-08-08 18:44:38 +0100772 case kExprBr: {
773 BreakDepthOperand operand(this, pc_);
774 Value val = {pc_, nullptr, kAstStmt};
775 if (operand.arity) val = Pop();
776 if (Validate(pc_, operand, control_)) {
777 BreakTo(operand.target, val);
778 }
779 len = 1 + operand.length;
780 Push(kAstEnd, nullptr);
781 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100782 }
Ben Murdochc5610432016-08-08 18:44:38 +0100783 case kExprBrIf: {
784 BreakDepthOperand operand(this, pc_);
785 Value cond = Pop(operand.arity, kAstI32);
786 Value val = {pc_, nullptr, kAstStmt};
787 if (operand.arity == 1) val = Pop();
788 if (Validate(pc_, operand, control_)) {
789 SsaEnv* fenv = ssa_env_;
790 SsaEnv* tenv = Split(fenv);
791 fenv->SetNotMerged();
792 BUILD(Branch, cond.node, &tenv->control, &fenv->control);
793 ssa_env_ = tenv;
794 BreakTo(operand.target, val);
795 ssa_env_ = fenv;
796 }
797 len = 1 + operand.length;
798 Push(kAstStmt, nullptr);
799 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100800 }
Ben Murdochc5610432016-08-08 18:44:38 +0100801 case kExprBrTable: {
802 BranchTableOperand operand(this, pc_);
803 if (Validate(pc_, operand, control_.size())) {
804 Value key = Pop(operand.arity, kAstI32);
805 Value val = {pc_, nullptr, kAstStmt};
806 if (operand.arity == 1) val = Pop();
807 if (failed()) break;
808
809 SsaEnv* break_env = ssa_env_;
810 if (operand.table_count > 0) {
811 // Build branches to the various blocks based on the table.
812 TFNode* sw = BUILD(Switch, operand.table_count + 1, key.node);
813
814 SsaEnv* copy = Steal(break_env);
815 ssa_env_ = copy;
Ben Murdoch61f157c2016-09-16 13:49:30 +0100816 for (uint32_t i = 0; i < operand.table_count + 1; ++i) {
Ben Murdochc5610432016-08-08 18:44:38 +0100817 uint16_t target = operand.read_entry(this, i);
818 ssa_env_ = Split(copy);
819 ssa_env_->control = (i == operand.table_count)
820 ? BUILD(IfDefault, sw)
821 : BUILD(IfValue, i, sw);
822 int depth = target;
823 Control* c = &control_[control_.size() - depth - 1];
824 MergeInto(c->end_env, &c->node, &c->type, val);
825 }
826 } else {
827 // Only a default target. Do the equivalent of br.
828 uint16_t target = operand.read_entry(this, 0);
829 int depth = target;
830 Control* c = &control_[control_.size() - depth - 1];
831 MergeInto(c->end_env, &c->node, &c->type, val);
832 }
833 // br_table ends the control flow like br.
834 ssa_env_ = break_env;
835 Push(kAstStmt, nullptr);
836 }
837 len = 1 + operand.length;
838 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100839 }
Ben Murdochc5610432016-08-08 18:44:38 +0100840 case kExprReturn: {
841 ReturnArityOperand operand(this, pc_);
842 if (operand.arity != sig_->return_count()) {
843 error(pc_, pc_ + 1, "arity mismatch in return");
844 }
845 DoReturn();
846 len = 1 + operand.length;
847 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100848 }
Ben Murdochc5610432016-08-08 18:44:38 +0100849 case kExprUnreachable: {
850 Push(kAstEnd, BUILD(Unreachable, position()));
851 ssa_env_->Kill(SsaEnv::kControlEnd);
852 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000853 }
Ben Murdochc5610432016-08-08 18:44:38 +0100854 case kExprI8Const: {
855 ImmI8Operand operand(this, pc_);
856 Push(kAstI32, BUILD(Int32Constant, operand.value));
857 len = 1 + operand.length;
858 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000859 }
Ben Murdochc5610432016-08-08 18:44:38 +0100860 case kExprI32Const: {
861 ImmI32Operand operand(this, pc_);
862 Push(kAstI32, BUILD(Int32Constant, operand.value));
863 len = 1 + operand.length;
864 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100865 }
Ben Murdochc5610432016-08-08 18:44:38 +0100866 case kExprI64Const: {
867 ImmI64Operand operand(this, pc_);
868 Push(kAstI64, BUILD(Int64Constant, operand.value));
869 len = 1 + operand.length;
870 break;
871 }
872 case kExprF32Const: {
873 ImmF32Operand operand(this, pc_);
874 Push(kAstF32, BUILD(Float32Constant, operand.value));
875 len = 1 + operand.length;
876 break;
877 }
878 case kExprF64Const: {
879 ImmF64Operand operand(this, pc_);
880 Push(kAstF64, BUILD(Float64Constant, operand.value));
881 len = 1 + operand.length;
882 break;
883 }
884 case kExprGetLocal: {
885 LocalIndexOperand operand(this, pc_);
886 if (Validate(pc_, operand)) {
887 if (build()) {
888 Push(operand.type, ssa_env_->locals[operand.index]);
889 } else {
890 Push(operand.type, nullptr);
891 }
892 }
893 len = 1 + operand.length;
894 break;
895 }
896 case kExprSetLocal: {
897 LocalIndexOperand operand(this, pc_);
898 if (Validate(pc_, operand)) {
899 Value val = Pop(0, local_type_vec_[operand.index]);
900 if (ssa_env_->locals) ssa_env_->locals[operand.index] = val.node;
901 Push(val.type, val.node);
902 }
903 len = 1 + operand.length;
904 break;
905 }
906 case kExprLoadGlobal: {
907 GlobalIndexOperand operand(this, pc_);
908 if (Validate(pc_, operand)) {
909 Push(operand.type, BUILD(LoadGlobal, operand.index));
910 }
911 len = 1 + operand.length;
912 break;
913 }
914 case kExprStoreGlobal: {
915 GlobalIndexOperand operand(this, pc_);
916 if (Validate(pc_, operand)) {
917 Value val = Pop(0, operand.type);
918 BUILD(StoreGlobal, operand.index, val.node);
919 Push(val.type, val.node);
920 }
921 len = 1 + operand.length;
922 break;
923 }
924 case kExprI32LoadMem8S:
925 len = DecodeLoadMem(kAstI32, MachineType::Int8());
926 break;
927 case kExprI32LoadMem8U:
928 len = DecodeLoadMem(kAstI32, MachineType::Uint8());
929 break;
930 case kExprI32LoadMem16S:
931 len = DecodeLoadMem(kAstI32, MachineType::Int16());
932 break;
933 case kExprI32LoadMem16U:
934 len = DecodeLoadMem(kAstI32, MachineType::Uint16());
935 break;
936 case kExprI32LoadMem:
937 len = DecodeLoadMem(kAstI32, MachineType::Int32());
938 break;
939
940 case kExprI64LoadMem8S:
941 len = DecodeLoadMem(kAstI64, MachineType::Int8());
942 break;
943 case kExprI64LoadMem8U:
944 len = DecodeLoadMem(kAstI64, MachineType::Uint8());
945 break;
946 case kExprI64LoadMem16S:
947 len = DecodeLoadMem(kAstI64, MachineType::Int16());
948 break;
949 case kExprI64LoadMem16U:
950 len = DecodeLoadMem(kAstI64, MachineType::Uint16());
951 break;
952 case kExprI64LoadMem32S:
953 len = DecodeLoadMem(kAstI64, MachineType::Int32());
954 break;
955 case kExprI64LoadMem32U:
956 len = DecodeLoadMem(kAstI64, MachineType::Uint32());
957 break;
958 case kExprI64LoadMem:
959 len = DecodeLoadMem(kAstI64, MachineType::Int64());
960 break;
961 case kExprF32LoadMem:
962 len = DecodeLoadMem(kAstF32, MachineType::Float32());
963 break;
964 case kExprF64LoadMem:
965 len = DecodeLoadMem(kAstF64, MachineType::Float64());
966 break;
967 case kExprI32StoreMem8:
968 len = DecodeStoreMem(kAstI32, MachineType::Int8());
969 break;
970 case kExprI32StoreMem16:
971 len = DecodeStoreMem(kAstI32, MachineType::Int16());
972 break;
973 case kExprI32StoreMem:
974 len = DecodeStoreMem(kAstI32, MachineType::Int32());
975 break;
976 case kExprI64StoreMem8:
977 len = DecodeStoreMem(kAstI64, MachineType::Int8());
978 break;
979 case kExprI64StoreMem16:
980 len = DecodeStoreMem(kAstI64, MachineType::Int16());
981 break;
982 case kExprI64StoreMem32:
983 len = DecodeStoreMem(kAstI64, MachineType::Int32());
984 break;
985 case kExprI64StoreMem:
986 len = DecodeStoreMem(kAstI64, MachineType::Int64());
987 break;
988 case kExprF32StoreMem:
989 len = DecodeStoreMem(kAstF32, MachineType::Float32());
990 break;
991 case kExprF64StoreMem:
992 len = DecodeStoreMem(kAstF64, MachineType::Float64());
993 break;
994
995 case kExprMemorySize:
996 Push(kAstI32, BUILD(MemSize, 0));
997 break;
998 case kExprGrowMemory: {
999 Value val = Pop(0, kAstI32);
1000 USE(val); // TODO(titzer): build node for grow memory
1001 Push(kAstI32, BUILD(Int32Constant, 0));
1002 break;
1003 }
1004 case kExprCallFunction: {
1005 CallFunctionOperand operand(this, pc_);
1006 if (Validate(pc_, operand)) {
1007 TFNode** buffer = PopArgs(operand.sig);
1008 TFNode* call =
1009 BUILD(CallDirect, operand.index, buffer, position());
1010 Push(GetReturnType(operand.sig), call);
1011 }
1012 len = 1 + operand.length;
1013 break;
1014 }
1015 case kExprCallIndirect: {
1016 CallIndirectOperand operand(this, pc_);
1017 if (Validate(pc_, operand)) {
1018 TFNode** buffer = PopArgs(operand.sig);
1019 Value index = Pop(0, kAstI32);
1020 if (buffer) buffer[0] = index.node;
1021 TFNode* call =
1022 BUILD(CallIndirect, operand.index, buffer, position());
1023 Push(GetReturnType(operand.sig), call);
1024 }
1025 len = 1 + operand.length;
1026 break;
1027 }
1028 case kExprCallImport: {
1029 CallImportOperand operand(this, pc_);
1030 if (Validate(pc_, operand)) {
1031 TFNode** buffer = PopArgs(operand.sig);
1032 TFNode* call =
1033 BUILD(CallImport, operand.index, buffer, position());
1034 Push(GetReturnType(operand.sig), call);
1035 }
1036 len = 1 + operand.length;
1037 break;
1038 }
1039 default:
1040 error("Invalid opcode");
1041 return;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001042 }
Ben Murdochc5610432016-08-08 18:44:38 +01001043 } // end complex bytecode
1044
1045#if DEBUG
1046 if (FLAG_trace_wasm_decoder) {
Ben Murdoch61f157c2016-09-16 13:49:30 +01001047 for (size_t i = 0; i < stack_.size(); ++i) {
Ben Murdochc5610432016-08-08 18:44:38 +01001048 Value& val = stack_[i];
1049 WasmOpcode opcode = static_cast<WasmOpcode>(*val.pc);
1050 PrintF(" %c@%d:%s", WasmOpcodes::ShortNameOf(val.type),
1051 static_cast<int>(val.pc - start_),
1052 WasmOpcodes::ShortOpcodeName(opcode));
1053 switch (opcode) {
1054 case kExprI32Const: {
1055 ImmI32Operand operand(this, val.pc);
1056 PrintF("[%d]", operand.value);
1057 break;
1058 }
1059 case kExprGetLocal: {
1060 LocalIndexOperand operand(this, val.pc);
1061 PrintF("[%u]", operand.index);
1062 break;
1063 }
1064 case kExprSetLocal: {
1065 LocalIndexOperand operand(this, val.pc);
1066 PrintF("[%u]", operand.index);
1067 break;
1068 }
1069 default:
1070 break;
1071 }
1072 }
1073 PrintF("\n");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001074 }
Ben Murdochc5610432016-08-08 18:44:38 +01001075#endif
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001076 pc_ += len;
1077 if (pc_ >= limit_) {
1078 // End of code reached or exceeded.
Ben Murdochc5610432016-08-08 18:44:38 +01001079 if (pc_ > limit_ && ok()) error("Beyond end of code");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001080 return;
1081 }
Ben Murdochc5610432016-08-08 18:44:38 +01001082 } // end decode loop
1083 } // end DecodeFunctionBody()
1084
1085 TFNode** PopArgs(FunctionSig* sig) {
1086 if (build()) {
1087 int count = static_cast<int>(sig->parameter_count());
1088 TFNode** buffer = builder_->Buffer(count + 1);
1089 buffer[0] = nullptr; // reserved for code object or function index.
1090 for (int i = count - 1; i >= 0; i--) {
1091 buffer[i + 1] = Pop(i, sig->GetParam(i)).node;
1092 }
1093 return buffer;
1094 } else {
1095 int count = static_cast<int>(sig->parameter_count());
1096 for (int i = count - 1; i >= 0; i--) {
1097 Pop(i, sig->GetParam(i));
1098 }
1099 return nullptr;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001100 }
1101 }
1102
Ben Murdochc5610432016-08-08 18:44:38 +01001103 LocalType GetReturnType(FunctionSig* sig) {
1104 return sig->return_count() == 0 ? kAstStmt : sig->GetReturn();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001105 }
1106
Ben Murdochc5610432016-08-08 18:44:38 +01001107 void PushBlock(SsaEnv* end_env) {
1108 int stack_depth = static_cast<int>(stack_.size());
1109 control_.push_back(
1110 {pc_, stack_depth, end_env, nullptr, nullptr, kAstEnd, false});
1111 }
1112
1113 void PushLoop(SsaEnv* end_env) {
1114 int stack_depth = static_cast<int>(stack_.size());
1115 control_.push_back(
1116 {pc_, stack_depth, end_env, nullptr, nullptr, kAstEnd, true});
1117 }
1118
1119 void PushIf(SsaEnv* end_env, SsaEnv* false_env) {
1120 int stack_depth = static_cast<int>(stack_.size());
1121 control_.push_back(
1122 {pc_, stack_depth, end_env, false_env, nullptr, kAstStmt, false});
1123 }
1124
1125 int DecodeLoadMem(LocalType type, MachineType mem_type) {
1126 MemoryAccessOperand operand(this, pc_);
1127 Value index = Pop(0, kAstI32);
Ben Murdoch61f157c2016-09-16 13:49:30 +01001128 TFNode* node = BUILD(LoadMem, type, mem_type, index.node, operand.offset,
1129 operand.alignment, position());
Ben Murdochc5610432016-08-08 18:44:38 +01001130 Push(type, node);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001131 return 1 + operand.length;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001132 }
1133
Ben Murdochc5610432016-08-08 18:44:38 +01001134 int DecodeStoreMem(LocalType type, MachineType mem_type) {
1135 MemoryAccessOperand operand(this, pc_);
1136 Value val = Pop(1, type);
1137 Value index = Pop(0, kAstI32);
Ben Murdoch61f157c2016-09-16 13:49:30 +01001138 BUILD(StoreMem, mem_type, index.node, operand.offset, operand.alignment,
1139 val.node, position());
Ben Murdochc5610432016-08-08 18:44:38 +01001140 Push(type, val.node);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001141 return 1 + operand.length;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001142 }
1143
Ben Murdochc5610432016-08-08 18:44:38 +01001144 void DoReturn() {
1145 int count = static_cast<int>(sig_->return_count());
1146 TFNode** buffer = nullptr;
1147 if (build()) buffer = builder_->Buffer(count);
1148
1149 // Pop return values off the stack in reverse order.
1150 for (int i = count - 1; i >= 0; i--) {
1151 Value val = Pop(i, sig_->GetReturn(i));
1152 if (buffer) buffer[i] = val.node;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001153 }
1154
Ben Murdochc5610432016-08-08 18:44:38 +01001155 Push(kAstEnd, BUILD(Return, count, buffer));
1156 ssa_env_->Kill(SsaEnv::kControlEnd);
1157 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001158
Ben Murdochc5610432016-08-08 18:44:38 +01001159 void Push(LocalType type, TFNode* node) {
1160 stack_.push_back({pc_, node, type});
1161 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001162
Ben Murdochc5610432016-08-08 18:44:38 +01001163 const char* SafeOpcodeNameAt(const byte* pc) {
1164 if (pc >= end_) return "<end>";
1165 return WasmOpcodes::ShortOpcodeName(static_cast<WasmOpcode>(*pc));
1166 }
1167
1168 Value Pop(int index, LocalType expected) {
1169 Value val = Pop();
1170 if (val.type != expected) {
1171 if (val.type != kAstEnd) {
1172 error(pc_, val.pc, "%s[%d] expected type %s, found %s of type %s",
1173 SafeOpcodeNameAt(pc_), index, WasmOpcodes::TypeName(expected),
1174 SafeOpcodeNameAt(val.pc), WasmOpcodes::TypeName(val.type));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001175 }
1176 }
Ben Murdochc5610432016-08-08 18:44:38 +01001177 return val;
1178 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001179
Ben Murdochc5610432016-08-08 18:44:38 +01001180 Value Pop() {
1181 size_t limit = control_.empty() ? 0 : control_.back().stack_depth;
1182 if (stack_.size() <= limit) {
1183 Value val = {pc_, nullptr, kAstStmt};
1184 error(pc_, pc_, "%s found empty stack", SafeOpcodeNameAt(pc_));
1185 return val;
1186 }
1187 Value val = stack_.back();
1188 stack_.pop_back();
1189 return val;
1190 }
1191
1192 Value PopUpTo(int stack_depth) {
1193 if (stack_depth == stack_.size()) {
1194 Value val = {pc_, nullptr, kAstStmt};
1195 return val;
1196 } else {
1197 DCHECK_LE(stack_depth, static_cast<int>(stack_.size()));
1198 Value val = Pop();
1199 stack_.resize(stack_depth);
1200 return val;
1201 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001202 }
1203
1204 int baserel(const byte* ptr) {
1205 return base_ ? static_cast<int>(ptr - base_) : 0;
1206 }
1207
1208 int startrel(const byte* ptr) { return static_cast<int>(ptr - start_); }
1209
Ben Murdochc5610432016-08-08 18:44:38 +01001210 void BreakTo(Control* block, Value& val) {
1211 if (block->is_loop) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001212 // This is the inner loop block, which does not have a value.
Ben Murdochc5610432016-08-08 18:44:38 +01001213 Goto(ssa_env_, block->end_env);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001214 } else {
1215 // Merge the value into the production for the block.
Ben Murdochc5610432016-08-08 18:44:38 +01001216 MergeInto(block->end_env, &block->node, &block->type, val);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001217 }
1218 }
1219
Ben Murdochc5610432016-08-08 18:44:38 +01001220 void MergeInto(SsaEnv* target, TFNode** node, LocalType* type, Value& val) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001221 if (!ssa_env_->go()) return;
Ben Murdochc5610432016-08-08 18:44:38 +01001222 DCHECK_NE(kAstEnd, val.type);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001223
1224 bool first = target->state == SsaEnv::kUnreachable;
1225 Goto(ssa_env_, target);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001226
1227 if (first) {
1228 // first merge to this environment; set the type and the node.
Ben Murdochc5610432016-08-08 18:44:38 +01001229 *type = val.type;
1230 *node = val.node;
1231 } else if (val.type == *type && val.type != kAstStmt) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001232 // merge with the existing value for this block.
Ben Murdochc5610432016-08-08 18:44:38 +01001233 *node = CreateOrMergeIntoPhi(*type, target->control, *node, val.node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001234 } else {
Ben Murdochc5610432016-08-08 18:44:38 +01001235 // types don't match, or block is already a stmt.
1236 *type = kAstStmt;
1237 *node = nullptr;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001238 }
1239 }
1240
1241 void SetEnv(const char* reason, SsaEnv* env) {
Ben Murdochda12d292016-06-02 14:46:10 +01001242#if DEBUG
Ben Murdochc5610432016-08-08 18:44:38 +01001243 if (FLAG_trace_wasm_decoder) {
1244 char state = 'X';
1245 if (env) {
1246 switch (env->state) {
1247 case SsaEnv::kReached:
1248 state = 'R';
1249 break;
1250 case SsaEnv::kUnreachable:
1251 state = 'U';
1252 break;
1253 case SsaEnv::kMerged:
1254 state = 'M';
1255 break;
1256 case SsaEnv::kControlEnd:
1257 state = 'E';
1258 break;
1259 }
1260 }
1261 PrintF(" env = %p, state = %c, reason = %s", static_cast<void*>(env),
1262 state, reason);
1263 if (env && env->control) {
1264 PrintF(", control = ");
1265 compiler::WasmGraphBuilder::PrintDebugName(env->control);
1266 }
1267 PrintF("\n");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001268 }
Ben Murdochda12d292016-06-02 14:46:10 +01001269#endif
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001270 ssa_env_ = env;
1271 if (builder_) {
1272 builder_->set_control_ptr(&env->control);
1273 builder_->set_effect_ptr(&env->effect);
1274 }
1275 }
1276
1277 void Goto(SsaEnv* from, SsaEnv* to) {
1278 DCHECK_NOT_NULL(to);
1279 if (!from->go()) return;
1280 switch (to->state) {
1281 case SsaEnv::kUnreachable: { // Overwrite destination.
1282 to->state = SsaEnv::kReached;
1283 to->locals = from->locals;
1284 to->control = from->control;
1285 to->effect = from->effect;
1286 break;
1287 }
1288 case SsaEnv::kReached: { // Create a new merge.
1289 to->state = SsaEnv::kMerged;
1290 if (!builder_) break;
1291 // Merge control.
1292 TFNode* controls[] = {to->control, from->control};
1293 TFNode* merge = builder_->Merge(2, controls);
1294 to->control = merge;
1295 // Merge effects.
1296 if (from->effect != to->effect) {
1297 TFNode* effects[] = {to->effect, from->effect, merge};
1298 to->effect = builder_->EffectPhi(2, effects, merge);
1299 }
1300 // Merge SSA values.
1301 for (int i = EnvironmentCount() - 1; i >= 0; i--) {
1302 TFNode* a = to->locals[i];
1303 TFNode* b = from->locals[i];
1304 if (a != b) {
1305 TFNode* vals[] = {a, b};
Ben Murdochda12d292016-06-02 14:46:10 +01001306 to->locals[i] = builder_->Phi(local_type_vec_[i], 2, vals, merge);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001307 }
1308 }
1309 break;
1310 }
1311 case SsaEnv::kMerged: {
1312 if (!builder_) break;
1313 TFNode* merge = to->control;
1314 // Extend the existing merge.
1315 builder_->AppendToMerge(merge, from->control);
1316 // Merge effects.
1317 if (builder_->IsPhiWithMerge(to->effect, merge)) {
Ben Murdochc5610432016-08-08 18:44:38 +01001318 builder_->AppendToPhi(to->effect, from->effect);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001319 } else if (to->effect != from->effect) {
1320 uint32_t count = builder_->InputCount(merge);
1321 TFNode** effects = builder_->Buffer(count);
1322 for (uint32_t j = 0; j < count - 1; j++) {
1323 effects[j] = to->effect;
1324 }
1325 effects[count - 1] = from->effect;
1326 to->effect = builder_->EffectPhi(count, effects, merge);
1327 }
1328 // Merge locals.
1329 for (int i = EnvironmentCount() - 1; i >= 0; i--) {
1330 TFNode* tnode = to->locals[i];
1331 TFNode* fnode = from->locals[i];
1332 if (builder_->IsPhiWithMerge(tnode, merge)) {
Ben Murdochc5610432016-08-08 18:44:38 +01001333 builder_->AppendToPhi(tnode, fnode);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001334 } else if (tnode != fnode) {
1335 uint32_t count = builder_->InputCount(merge);
1336 TFNode** vals = builder_->Buffer(count);
1337 for (uint32_t j = 0; j < count - 1; j++) {
1338 vals[j] = tnode;
1339 }
1340 vals[count - 1] = fnode;
Ben Murdochda12d292016-06-02 14:46:10 +01001341 to->locals[i] =
1342 builder_->Phi(local_type_vec_[i], count, vals, merge);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001343 }
1344 }
1345 break;
1346 }
1347 default:
1348 UNREACHABLE();
1349 }
1350 return from->Kill();
1351 }
1352
1353 TFNode* CreateOrMergeIntoPhi(LocalType type, TFNode* merge, TFNode* tnode,
1354 TFNode* fnode) {
1355 if (builder_->IsPhiWithMerge(tnode, merge)) {
Ben Murdochc5610432016-08-08 18:44:38 +01001356 builder_->AppendToPhi(tnode, fnode);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001357 } else if (tnode != fnode) {
1358 uint32_t count = builder_->InputCount(merge);
1359 TFNode** vals = builder_->Buffer(count);
1360 for (uint32_t j = 0; j < count - 1; j++) vals[j] = tnode;
1361 vals[count - 1] = fnode;
1362 return builder_->Phi(type, count, vals, merge);
1363 }
1364 return tnode;
1365 }
1366
Ben Murdochda12d292016-06-02 14:46:10 +01001367 void PrepareForLoop(const byte* pc, SsaEnv* env) {
1368 if (!env->go()) return;
1369 env->state = SsaEnv::kMerged;
1370 if (!builder_) return;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001371
Ben Murdochda12d292016-06-02 14:46:10 +01001372 env->control = builder_->Loop(env->control);
1373 env->effect = builder_->EffectPhi(1, &env->effect, env->control);
1374 builder_->Terminate(env->effect, env->control);
1375 if (FLAG_wasm_loop_assignment_analysis) {
1376 BitVector* assigned = AnalyzeLoopAssignment(pc);
1377 if (assigned != nullptr) {
1378 // Only introduce phis for variables assigned in this loop.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001379 for (int i = EnvironmentCount() - 1; i >= 0; i--) {
Ben Murdochda12d292016-06-02 14:46:10 +01001380 if (!assigned->Contains(i)) continue;
1381 env->locals[i] = builder_->Phi(local_type_vec_[i], 1, &env->locals[i],
1382 env->control);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001383 }
Ben Murdochda12d292016-06-02 14:46:10 +01001384 return;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001385 }
1386 }
Ben Murdochda12d292016-06-02 14:46:10 +01001387
1388 // Conservatively introduce phis for all local variables.
1389 for (int i = EnvironmentCount() - 1; i >= 0; i--) {
1390 env->locals[i] =
1391 builder_->Phi(local_type_vec_[i], 1, &env->locals[i], env->control);
1392 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001393 }
1394
1395 // Create a complete copy of the {from}.
1396 SsaEnv* Split(SsaEnv* from) {
1397 DCHECK_NOT_NULL(from);
1398 SsaEnv* result = reinterpret_cast<SsaEnv*>(zone_->New(sizeof(SsaEnv)));
1399 size_t size = sizeof(TFNode*) * EnvironmentCount();
1400 result->control = from->control;
1401 result->effect = from->effect;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001402
1403 if (from->go()) {
1404 result->state = SsaEnv::kReached;
1405 result->locals =
1406 size > 0 ? reinterpret_cast<TFNode**>(zone_->New(size)) : nullptr;
1407 memcpy(result->locals, from->locals, size);
1408 } else {
1409 result->state = SsaEnv::kUnreachable;
1410 result->locals = nullptr;
1411 }
1412
1413 return result;
1414 }
1415
1416 // Create a copy of {from} that steals its state and leaves {from}
1417 // unreachable.
1418 SsaEnv* Steal(SsaEnv* from) {
1419 DCHECK_NOT_NULL(from);
1420 if (!from->go()) return UnreachableEnv();
1421 SsaEnv* result = reinterpret_cast<SsaEnv*>(zone_->New(sizeof(SsaEnv)));
1422 result->state = SsaEnv::kReached;
1423 result->locals = from->locals;
1424 result->control = from->control;
1425 result->effect = from->effect;
1426 from->Kill(SsaEnv::kUnreachable);
1427 return result;
1428 }
1429
1430 // Create an unreachable environment.
1431 SsaEnv* UnreachableEnv() {
1432 SsaEnv* result = reinterpret_cast<SsaEnv*>(zone_->New(sizeof(SsaEnv)));
1433 result->state = SsaEnv::kUnreachable;
1434 result->control = nullptr;
1435 result->effect = nullptr;
1436 result->locals = nullptr;
1437 return result;
1438 }
1439
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001440 int EnvironmentCount() {
Ben Murdochda12d292016-06-02 14:46:10 +01001441 if (builder_) return static_cast<int>(local_type_vec_.size());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001442 return 0; // if we aren't building a graph, don't bother with SSA renaming.
1443 }
1444
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001445 virtual void onFirstError() {
1446 limit_ = start_; // Terminate decoding loop.
1447 builder_ = nullptr; // Don't build any more nodes.
Ben Murdochc5610432016-08-08 18:44:38 +01001448 TRACE(" !%s\n", error_msg_.get());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001449 }
Ben Murdochda12d292016-06-02 14:46:10 +01001450 BitVector* AnalyzeLoopAssignment(const byte* pc) {
1451 if (pc >= limit_) return nullptr;
1452 if (*pc != kExprLoop) return nullptr;
1453
1454 BitVector* assigned =
Ben Murdochc5610432016-08-08 18:44:38 +01001455 new (zone_) BitVector(static_cast<int>(local_type_vec_.size()), zone_);
1456 int depth = 0;
Ben Murdochda12d292016-06-02 14:46:10 +01001457 // Iteratively process all AST nodes nested inside the loop.
Ben Murdoch61f157c2016-09-16 13:49:30 +01001458 while (pc < limit_ && ok()) {
Ben Murdochda12d292016-06-02 14:46:10 +01001459 WasmOpcode opcode = static_cast<WasmOpcode>(*pc);
Ben Murdoch61f157c2016-09-16 13:49:30 +01001460 unsigned length = 1;
Ben Murdochc5610432016-08-08 18:44:38 +01001461 switch (opcode) {
1462 case kExprLoop:
1463 case kExprIf:
1464 case kExprBlock:
1465 depth++;
1466 DCHECK_EQ(1, OpcodeLength(pc));
1467 break;
1468 case kExprSetLocal: {
1469 LocalIndexOperand operand(this, pc);
1470 if (assigned->length() > 0 &&
1471 static_cast<int>(operand.index) < assigned->length()) {
1472 // Unverified code might have an out-of-bounds index.
1473 assigned->Add(operand.index);
1474 }
1475 length = 1 + operand.length;
1476 break;
Ben Murdochda12d292016-06-02 14:46:10 +01001477 }
Ben Murdochc5610432016-08-08 18:44:38 +01001478 case kExprEnd:
1479 depth--;
1480 break;
1481 default:
1482 length = OpcodeLength(pc);
1483 break;
Ben Murdochda12d292016-06-02 14:46:10 +01001484 }
Ben Murdochc5610432016-08-08 18:44:38 +01001485 if (depth <= 0) break;
Ben Murdochda12d292016-06-02 14:46:10 +01001486 pc += length;
Ben Murdochda12d292016-06-02 14:46:10 +01001487 }
Ben Murdoch61f157c2016-09-16 13:49:30 +01001488 return ok() ? assigned : nullptr;
Ben Murdochda12d292016-06-02 14:46:10 +01001489 }
Ben Murdochc5610432016-08-08 18:44:38 +01001490
1491 inline wasm::WasmCodePosition position() {
1492 int offset = static_cast<int>(pc_ - start_);
1493 DCHECK_EQ(pc_ - start_, offset); // overflows cannot happen
1494 return offset;
1495 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001496};
1497
Ben Murdochda12d292016-06-02 14:46:10 +01001498bool DecodeLocalDecls(AstLocalDecls& decls, const byte* start,
1499 const byte* end) {
1500 base::AccountingAllocator allocator;
1501 Zone tmp(&allocator);
1502 FunctionBody body = {nullptr, nullptr, nullptr, start, end};
1503 SR_WasmDecoder decoder(&tmp, nullptr, body);
1504 return decoder.DecodeLocalDecls(decls);
1505}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001506
Ben Murdochda12d292016-06-02 14:46:10 +01001507TreeResult VerifyWasmCode(base::AccountingAllocator* allocator,
1508 FunctionBody& body) {
1509 Zone zone(allocator);
1510 SR_WasmDecoder decoder(&zone, nullptr, body);
Ben Murdochc5610432016-08-08 18:44:38 +01001511 decoder.Decode();
1512 return decoder.toResult<Tree*>(nullptr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001513}
1514
Ben Murdochda12d292016-06-02 14:46:10 +01001515TreeResult BuildTFGraph(base::AccountingAllocator* allocator,
1516 TFBuilder* builder, FunctionBody& body) {
1517 Zone zone(allocator);
1518 SR_WasmDecoder decoder(&zone, builder, body);
Ben Murdochc5610432016-08-08 18:44:38 +01001519 decoder.Decode();
1520 return decoder.toResult<Tree*>(nullptr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001521}
1522
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001523std::ostream& operator<<(std::ostream& os, const Tree& tree) {
1524 if (tree.pc == nullptr) {
1525 os << "null";
1526 return os;
1527 }
1528 PrintF("%s", WasmOpcodes::OpcodeName(tree.opcode()));
1529 if (tree.count > 0) os << "(";
Ben Murdoch61f157c2016-09-16 13:49:30 +01001530 for (uint32_t i = 0; i < tree.count; ++i) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001531 if (i > 0) os << ", ";
1532 os << *tree.children[i];
1533 }
1534 if (tree.count > 0) os << ")";
1535 return os;
1536}
1537
Ben Murdoch61f157c2016-09-16 13:49:30 +01001538unsigned OpcodeLength(const byte* pc, const byte* end) {
Ben Murdochda12d292016-06-02 14:46:10 +01001539 WasmDecoder decoder(nullptr, nullptr, pc, end);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001540 return decoder.OpcodeLength(pc);
1541}
1542
Ben Murdoch61f157c2016-09-16 13:49:30 +01001543unsigned OpcodeArity(const byte* pc, const byte* end) {
Ben Murdochc5610432016-08-08 18:44:38 +01001544 WasmDecoder decoder(nullptr, nullptr, pc, end);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001545 return decoder.OpcodeArity(pc);
1546}
1547
Ben Murdochc5610432016-08-08 18:44:38 +01001548void PrintAstForDebugging(const byte* start, const byte* end) {
Ben Murdochc5610432016-08-08 18:44:38 +01001549 base::AccountingAllocator allocator;
Ben Murdoch61f157c2016-09-16 13:49:30 +01001550 OFStream os(stdout);
1551 PrintAst(&allocator, FunctionBodyForTesting(start, end), os, nullptr);
Ben Murdochc5610432016-08-08 18:44:38 +01001552}
1553
Ben Murdoch61f157c2016-09-16 13:49:30 +01001554bool PrintAst(base::AccountingAllocator* allocator, const FunctionBody& body,
1555 std::ostream& os,
1556 std::vector<std::tuple<uint32_t, int, int>>* offset_table) {
Ben Murdochda12d292016-06-02 14:46:10 +01001557 Zone zone(allocator);
1558 SR_WasmDecoder decoder(&zone, nullptr, body);
Ben Murdoch61f157c2016-09-16 13:49:30 +01001559 int line_nr = 0;
Ben Murdochda12d292016-06-02 14:46:10 +01001560
1561 // Print the function signature.
1562 if (body.sig) {
1563 os << "// signature: " << *body.sig << std::endl;
Ben Murdoch61f157c2016-09-16 13:49:30 +01001564 ++line_nr;
Ben Murdochda12d292016-06-02 14:46:10 +01001565 }
1566
1567 // Print the local declarations.
1568 AstLocalDecls decls(&zone);
1569 decoder.DecodeLocalDecls(decls);
1570 const byte* pc = decoder.pc();
1571 if (body.start != decoder.pc()) {
Ben Murdochc5610432016-08-08 18:44:38 +01001572 os << "// locals: ";
Ben Murdochda12d292016-06-02 14:46:10 +01001573 for (auto p : decls.local_types) {
1574 LocalType type = p.first;
1575 uint32_t count = p.second;
1576 os << " " << count << " " << WasmOpcodes::TypeName(type);
1577 }
1578 os << std::endl;
1579
1580 for (const byte* locals = body.start; locals < pc; locals++) {
Ben Murdoch61f157c2016-09-16 13:49:30 +01001581 os << (locals == body.start ? "0x" : " 0x") << AsHex(*locals, 2) << ",";
Ben Murdochda12d292016-06-02 14:46:10 +01001582 }
Ben Murdochc5610432016-08-08 18:44:38 +01001583 os << std::endl;
Ben Murdoch61f157c2016-09-16 13:49:30 +01001584 ++line_nr;
Ben Murdochda12d292016-06-02 14:46:10 +01001585 }
1586
Ben Murdoch61f157c2016-09-16 13:49:30 +01001587 os << "// body: " << std::endl;
1588 ++line_nr;
1589 unsigned control_depth = 0;
Ben Murdochda12d292016-06-02 14:46:10 +01001590 while (pc < body.end) {
Ben Murdoch61f157c2016-09-16 13:49:30 +01001591 unsigned length = decoder.OpcodeLength(pc);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001592
Ben Murdoch097c5b22016-05-18 11:27:45 +01001593 WasmOpcode opcode = static_cast<WasmOpcode>(*pc);
Ben Murdochc5610432016-08-08 18:44:38 +01001594 if (opcode == kExprElse) control_depth--;
1595
Ben Murdoch61f157c2016-09-16 13:49:30 +01001596 int num_whitespaces = control_depth < 32 ? 2 * control_depth : 64;
1597 if (offset_table) {
1598 offset_table->push_back(
1599 std::make_tuple(pc - body.start, line_nr, num_whitespaces));
1600 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001601
Ben Murdoch61f157c2016-09-16 13:49:30 +01001602 // 64 whitespaces
1603 const char* padding =
1604 " ";
1605 os.write(padding, num_whitespaces);
1606 os << "k" << WasmOpcodes::OpcodeName(opcode) << ",";
1607
1608 for (size_t i = 1; i < length; ++i) {
1609 os << " " << AsHex(pc[i], 2) << ",";
Ben Murdoch097c5b22016-05-18 11:27:45 +01001610 }
Ben Murdochda12d292016-06-02 14:46:10 +01001611
Ben Murdochc5610432016-08-08 18:44:38 +01001612 switch (opcode) {
1613 case kExprIf:
1614 case kExprElse:
1615 case kExprLoop:
1616 case kExprBlock:
1617 os << " // @" << static_cast<int>(pc - body.start);
1618 control_depth++;
1619 break;
1620 case kExprEnd:
1621 os << " // @" << static_cast<int>(pc - body.start);
1622 control_depth--;
1623 break;
1624 case kExprBr: {
1625 BreakDepthOperand operand(&decoder, pc);
1626 os << " // arity=" << operand.arity << " depth=" << operand.depth;
1627 break;
Ben Murdochda12d292016-06-02 14:46:10 +01001628 }
Ben Murdochc5610432016-08-08 18:44:38 +01001629 case kExprBrIf: {
1630 BreakDepthOperand operand(&decoder, pc);
1631 os << " // arity=" << operand.arity << " depth" << operand.depth;
1632 break;
1633 }
1634 case kExprBrTable: {
1635 BranchTableOperand operand(&decoder, pc);
1636 os << " // arity=" << operand.arity
1637 << " entries=" << operand.table_count;
1638 break;
1639 }
1640 case kExprCallIndirect: {
1641 CallIndirectOperand operand(&decoder, pc);
Ben Murdoch61f157c2016-09-16 13:49:30 +01001642 if (decoder.Complete(pc, operand)) {
Ben Murdochc5610432016-08-08 18:44:38 +01001643 os << " // sig #" << operand.index << ": " << *operand.sig;
1644 } else {
1645 os << " // arity=" << operand.arity << " sig #" << operand.index;
1646 }
1647 break;
1648 }
1649 case kExprCallImport: {
1650 CallImportOperand operand(&decoder, pc);
Ben Murdoch61f157c2016-09-16 13:49:30 +01001651 if (decoder.Complete(pc, operand)) {
Ben Murdochc5610432016-08-08 18:44:38 +01001652 os << " // import #" << operand.index << ": " << *operand.sig;
1653 } else {
1654 os << " // arity=" << operand.arity << " import #" << operand.index;
1655 }
1656 break;
1657 }
1658 case kExprCallFunction: {
1659 CallFunctionOperand operand(&decoder, pc);
Ben Murdoch61f157c2016-09-16 13:49:30 +01001660 if (decoder.Complete(pc, operand)) {
Ben Murdochc5610432016-08-08 18:44:38 +01001661 os << " // function #" << operand.index << ": " << *operand.sig;
1662 } else {
1663 os << " // arity=" << operand.arity << " function #" << operand.index;
1664 }
1665 break;
1666 }
1667 case kExprReturn: {
1668 ReturnArityOperand operand(&decoder, pc);
1669 os << " // arity=" << operand.arity;
1670 break;
1671 }
1672 default:
1673 break;
1674 }
Ben Murdochda12d292016-06-02 14:46:10 +01001675
Ben Murdoch097c5b22016-05-18 11:27:45 +01001676 pc += length;
Ben Murdochc5610432016-08-08 18:44:38 +01001677 os << std::endl;
Ben Murdoch61f157c2016-09-16 13:49:30 +01001678 ++line_nr;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001679 }
Ben Murdoch61f157c2016-09-16 13:49:30 +01001680
1681 return decoder.ok();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001682}
1683
Ben Murdochda12d292016-06-02 14:46:10 +01001684BitVector* AnalyzeLoopAssignmentForTesting(Zone* zone, size_t num_locals,
Ben Murdoch097c5b22016-05-18 11:27:45 +01001685 const byte* start, const byte* end) {
Ben Murdochda12d292016-06-02 14:46:10 +01001686 FunctionBody body = {nullptr, nullptr, nullptr, start, end};
1687 SR_WasmDecoder decoder(zone, nullptr, body);
1688 return decoder.AnalyzeLoopAssignmentForTesting(start, num_locals);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001689}
1690
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001691} // namespace wasm
1692} // namespace internal
1693} // namespace v8