Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(94)

Side by Side Diff: src/wasm/ast-decoder.cc

Issue 1763433002: [wasm] Rework encoding of local declarations. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 the V8 project authors. All rights reserved. 1 // Copyright 2015 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/base/platform/elapsed-timer.h" 5 #include "src/base/platform/elapsed-timer.h"
6 #include "src/signature.h" 6 #include "src/signature.h"
7 7
8 #include "src/bit-vector.h" 8 #include "src/bit-vector.h"
9 #include "src/flags.h" 9 #include "src/flags.h"
10 #include "src/handles.h" 10 #include "src/handles.h"
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
45 struct Production { 45 struct Production {
46 Tree* tree; // the root of the syntax tree. 46 Tree* tree; // the root of the syntax tree.
47 int index; // the current index into the children of the tree. 47 int index; // the current index into the children of the tree.
48 48
49 WasmOpcode opcode() const { return static_cast<WasmOpcode>(*pc()); } 49 WasmOpcode opcode() const { return static_cast<WasmOpcode>(*pc()); }
50 const byte* pc() const { return tree->pc; } 50 const byte* pc() const { return tree->pc; }
51 bool done() const { return index >= static_cast<int>(tree->count); } 51 bool done() const { return index >= static_cast<int>(tree->count); }
52 Tree* last() const { return index > 0 ? tree->children[index - 1] : nullptr; } 52 Tree* last() const { return index > 0 ? tree->children[index - 1] : nullptr; }
53 }; 53 };
54 54
55
56 // An SsaEnv environment carries the current local variable renaming 55 // An SsaEnv environment carries the current local variable renaming
57 // as well as the current effect and control dependency in the TF graph. 56 // as well as the current effect and control dependency in the TF graph.
58 // It maintains a control state that tracks whether the environment 57 // It maintains a control state that tracks whether the environment
59 // is reachable, has reached a control end, or has been merged. 58 // is reachable, has reached a control end, or has been merged.
60 struct SsaEnv { 59 struct SsaEnv {
61 enum State { kControlEnd, kUnreachable, kReached, kMerged }; 60 enum State { kControlEnd, kUnreachable, kReached, kMerged };
62 61
63 State state; 62 State state;
64 TFNode* control; 63 TFNode* control;
65 TFNode* effect; 64 TFNode* effect;
66 TFNode** locals; 65 TFNode** locals;
67 66
68 bool go() { return state >= kReached; } 67 bool go() { return state >= kReached; }
69 void Kill(State new_state = kControlEnd) { 68 void Kill(State new_state = kControlEnd) {
70 state = new_state; 69 state = new_state;
71 locals = nullptr; 70 locals = nullptr;
72 control = nullptr; 71 control = nullptr;
73 effect = nullptr; 72 effect = nullptr;
74 } 73 }
75 }; 74 };
76 75
77
78 // An entry in the stack of blocks during decoding. 76 // An entry in the stack of blocks during decoding.
79 struct Block { 77 struct Block {
80 SsaEnv* ssa_env; // SSA renaming environment. 78 SsaEnv* ssa_env; // SSA renaming environment.
81 int stack_depth; // production stack depth. 79 int stack_depth; // production stack depth.
82 }; 80 };
83 81
84
85 // An entry in the stack of ifs during decoding. 82 // An entry in the stack of ifs during decoding.
86 struct IfEnv { 83 struct IfEnv {
87 SsaEnv* false_env; 84 SsaEnv* false_env;
88 SsaEnv* merge_env; 85 SsaEnv* merge_env;
89 SsaEnv** case_envs; 86 SsaEnv** case_envs;
90 }; 87 };
91 88
92
93 // Macros that build nodes only if there is a graph and the current SSA 89 // Macros that build nodes only if there is a graph and the current SSA
94 // environment is reachable from start. This avoids problems with malformed 90 // environment is reachable from start. This avoids problems with malformed
95 // TF graphs when decoding inputs that have unreachable code. 91 // TF graphs when decoding inputs that have unreachable code.
96 #define BUILD(func, ...) (build() ? builder_->func(__VA_ARGS__) : nullptr) 92 #define BUILD(func, ...) (build() ? builder_->func(__VA_ARGS__) : nullptr)
97 #define BUILD0(func) (build() ? builder_->func() : nullptr) 93 #define BUILD0(func) (build() ? builder_->func() : nullptr)
98 94
99
100 // Generic Wasm bytecode decoder with utilities for decoding operands, 95 // Generic Wasm bytecode decoder with utilities for decoding operands,
101 // lengths, etc. 96 // lengths, etc.
102 class WasmDecoder : public Decoder { 97 class WasmDecoder : public Decoder {
103 public: 98 public:
104 WasmDecoder() : Decoder(nullptr, nullptr), function_env_(nullptr) {} 99 WasmDecoder(ModuleEnv* module, FunctionSig* sig, const byte* start,
105 WasmDecoder(FunctionEnv* env, const byte* start, const byte* end) 100 const byte* end)
106 : Decoder(start, end), function_env_(env) {} 101 : Decoder(start, end),
107 FunctionEnv* function_env_; 102 module_(module),
108 103 sig_(sig),
109 void Reset(FunctionEnv* function_env, const byte* start, const byte* end) { 104 total_locals_(0),
110 Decoder::Reset(start, end); 105 local_types_(nullptr) {}
111 function_env_ = function_env; 106 ModuleEnv* module_;
112 } 107 FunctionSig* sig_;
108 size_t total_locals_;
109 ZoneVector<LocalType>* local_types_;
113 110
114 byte ByteOperand(const byte* pc, const char* msg = "missing 1-byte operand") { 111 byte ByteOperand(const byte* pc, const char* msg = "missing 1-byte operand") {
115 if ((pc + sizeof(byte)) >= limit_) { 112 if ((pc + sizeof(byte)) >= limit_) {
116 error(pc, msg); 113 error(pc, msg);
117 return 0; 114 return 0;
118 } 115 }
119 return pc[1]; 116 return pc[1];
120 } 117 }
121 118
122 uint32_t Uint32Operand(const byte* pc) { 119 uint32_t Uint32Operand(const byte* pc) {
123 if ((pc + sizeof(uint32_t)) >= limit_) { 120 if ((pc + sizeof(uint32_t)) >= limit_) {
124 error(pc, "missing 4-byte operand"); 121 error(pc, "missing 4-byte operand");
125 return 0; 122 return 0;
126 } 123 }
127 return read_u32(pc + 1); 124 return read_u32(pc + 1);
128 } 125 }
129 126
130 uint64_t Uint64Operand(const byte* pc) { 127 uint64_t Uint64Operand(const byte* pc) {
131 if ((pc + sizeof(uint64_t)) >= limit_) { 128 if ((pc + sizeof(uint64_t)) >= limit_) {
132 error(pc, "missing 8-byte operand"); 129 error(pc, "missing 8-byte operand");
133 return 0; 130 return 0;
134 } 131 }
135 return read_u64(pc + 1); 132 return read_u64(pc + 1);
136 } 133 }
137 134
138 inline bool Validate(const byte* pc, LocalIndexOperand& operand) { 135 inline bool Validate(const byte* pc, LocalIndexOperand& operand) {
139 if (operand.index < function_env_->total_locals) { 136 if (operand.index < total_locals_) {
140 operand.type = function_env_->GetLocalType(operand.index); 137 if (local_types_) {
138 operand.type = local_types_->at(operand.index);
139 } else {
140 operand.type = kAstStmt;
141 }
141 return true; 142 return true;
142 } 143 }
143 error(pc, pc + 1, "invalid local index"); 144 error(pc, pc + 1, "invalid local index");
144 return false; 145 return false;
145 } 146 }
146 147
147 inline bool Validate(const byte* pc, GlobalIndexOperand& operand) { 148 inline bool Validate(const byte* pc, GlobalIndexOperand& operand) {
148 ModuleEnv* m = function_env_->module; 149 ModuleEnv* m = module_;
149 if (m && m->module && operand.index < m->module->globals.size()) { 150 if (m && m->module && operand.index < m->module->globals.size()) {
150 operand.machine_type = m->module->globals[operand.index].type; 151 operand.machine_type = m->module->globals[operand.index].type;
151 operand.type = WasmOpcodes::LocalTypeFor(operand.machine_type); 152 operand.type = WasmOpcodes::LocalTypeFor(operand.machine_type);
152 return true; 153 return true;
153 } 154 }
154 error(pc, pc + 1, "invalid global index"); 155 error(pc, pc + 1, "invalid global index");
155 return false; 156 return false;
156 } 157 }
157 158
158 inline bool Validate(const byte* pc, FunctionIndexOperand& operand) { 159 inline bool Validate(const byte* pc, FunctionIndexOperand& operand) {
159 ModuleEnv* m = function_env_->module; 160 ModuleEnv* m = module_;
160 if (m && m->module && operand.index < m->module->functions.size()) { 161 if (m && m->module && operand.index < m->module->functions.size()) {
161 operand.sig = m->module->functions[operand.index].sig; 162 operand.sig = m->module->functions[operand.index].sig;
162 return true; 163 return true;
163 } 164 }
164 error(pc, pc + 1, "invalid function index"); 165 error(pc, pc + 1, "invalid function index");
165 return false; 166 return false;
166 } 167 }
167 168
168 inline bool Validate(const byte* pc, SignatureIndexOperand& operand) { 169 inline bool Validate(const byte* pc, SignatureIndexOperand& operand) {
169 ModuleEnv* m = function_env_->module; 170 ModuleEnv* m = module_;
170 if (m && m->module && operand.index < m->module->signatures.size()) { 171 if (m && m->module && operand.index < m->module->signatures.size()) {
171 operand.sig = m->module->signatures[operand.index]; 172 operand.sig = m->module->signatures[operand.index];
172 return true; 173 return true;
173 } 174 }
174 error(pc, pc + 1, "invalid signature index"); 175 error(pc, pc + 1, "invalid signature index");
175 return false; 176 return false;
176 } 177 }
177 178
178 inline bool Validate(const byte* pc, ImportIndexOperand& operand) { 179 inline bool Validate(const byte* pc, ImportIndexOperand& operand) {
179 ModuleEnv* m = function_env_->module; 180 ModuleEnv* m = module_;
180 if (m && m->module && operand.index < m->module->import_table.size()) { 181 if (m && m->module && operand.index < m->module->import_table.size()) {
181 operand.sig = m->module->import_table[operand.index].sig; 182 operand.sig = m->module->import_table[operand.index].sig;
182 return true; 183 return true;
183 } 184 }
184 error(pc, pc + 1, "invalid signature index"); 185 error(pc, pc + 1, "invalid signature index");
185 return false; 186 return false;
186 } 187 }
187 188
188 inline bool Validate(const byte* pc, BreakDepthOperand& operand, 189 inline bool Validate(const byte* pc, BreakDepthOperand& operand,
189 ZoneVector<Block>& blocks) { 190 ZoneVector<Block>& blocks) {
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
255 256
256 case kExprBlock: 257 case kExprBlock:
257 case kExprLoop: { 258 case kExprLoop: {
258 BlockCountOperand operand(this, pc); 259 BlockCountOperand operand(this, pc);
259 return operand.count; 260 return operand.count;
260 } 261 }
261 262
262 case kExprCallFunction: { 263 case kExprCallFunction: {
263 FunctionIndexOperand operand(this, pc); 264 FunctionIndexOperand operand(this, pc);
264 return static_cast<int>( 265 return static_cast<int>(
265 function_env_->module->GetFunctionSignature(operand.index) 266 module_->GetFunctionSignature(operand.index)->parameter_count());
266 ->parameter_count());
267 } 267 }
268 case kExprCallIndirect: { 268 case kExprCallIndirect: {
269 SignatureIndexOperand operand(this, pc); 269 SignatureIndexOperand operand(this, pc);
270 return 1 + static_cast<int>( 270 return 1 + static_cast<int>(
271 function_env_->module->GetSignature(operand.index) 271 module_->GetSignature(operand.index)->parameter_count());
272 ->parameter_count());
273 } 272 }
274 case kExprCallImport: { 273 case kExprCallImport: {
275 ImportIndexOperand operand(this, pc); 274 ImportIndexOperand operand(this, pc);
276 return static_cast<int>( 275 return static_cast<int>(
277 function_env_->module->GetImportSignature(operand.index) 276 module_->GetImportSignature(operand.index)->parameter_count());
278 ->parameter_count());
279 } 277 }
280 case kExprReturn: { 278 case kExprReturn: {
281 return static_cast<int>(function_env_->sig->return_count()); 279 return static_cast<int>(sig_->return_count());
282 } 280 }
283 case kExprTableSwitch: { 281 case kExprTableSwitch: {
284 TableSwitchOperand operand(this, pc); 282 TableSwitchOperand operand(this, pc);
285 return 1 + operand.case_count; 283 return 1 + operand.case_count;
286 } 284 }
287 285
288 #define DECLARE_OPCODE_CASE(name, opcode, sig) \ 286 #define DECLARE_OPCODE_CASE(name, opcode, sig) \
289 case kExpr##name: \ 287 case kExpr##name: \
290 return kArity_##sig; 288 return kArity_##sig;
291 289
292 FOREACH_LOAD_MEM_OPCODE(DECLARE_OPCODE_CASE) 290 FOREACH_LOAD_MEM_OPCODE(DECLARE_OPCODE_CASE)
293 FOREACH_STORE_MEM_OPCODE(DECLARE_OPCODE_CASE) 291 FOREACH_STORE_MEM_OPCODE(DECLARE_OPCODE_CASE)
294 FOREACH_MISC_MEM_OPCODE(DECLARE_OPCODE_CASE) 292 FOREACH_MISC_MEM_OPCODE(DECLARE_OPCODE_CASE)
295 FOREACH_SIMPLE_OPCODE(DECLARE_OPCODE_CASE) 293 FOREACH_SIMPLE_OPCODE(DECLARE_OPCODE_CASE)
296 #undef DECLARE_OPCODE_CASE 294 #undef DECLARE_OPCODE_CASE
295 case kExprDeclLocals:
296 default:
297 UNREACHABLE();
298 return 0;
297 } 299 }
298 UNREACHABLE();
299 return 0;
300 } 300 }
301 301
302 int OpcodeLength(const byte* pc) { 302 int OpcodeLength(const byte* pc) {
303 switch (static_cast<WasmOpcode>(*pc)) { 303 switch (static_cast<WasmOpcode>(*pc)) {
304 #define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name: 304 #define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name:
305 FOREACH_LOAD_MEM_OPCODE(DECLARE_OPCODE_CASE) 305 FOREACH_LOAD_MEM_OPCODE(DECLARE_OPCODE_CASE)
306 FOREACH_STORE_MEM_OPCODE(DECLARE_OPCODE_CASE) 306 FOREACH_STORE_MEM_OPCODE(DECLARE_OPCODE_CASE)
307 #undef DECLARE_OPCODE_CASE 307 #undef DECLARE_OPCODE_CASE
308 { 308 {
309 MemoryAccessOperand operand(this, pc); 309 MemoryAccessOperand operand(this, pc);
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
358 358
359 default: 359 default:
360 return 1; 360 return 1;
361 } 361 }
362 } 362 }
363 }; 363 };
364 364
365 365
366 // A shift-reduce-parser strategy for decoding Wasm code that uses an explicit 366 // A shift-reduce-parser strategy for decoding Wasm code that uses an explicit
367 // shift-reduce strategy with multiple internal stacks. 367 // shift-reduce strategy with multiple internal stacks.
368 class LR_WasmDecoder : public WasmDecoder { 368 class SR_WasmDecoder : public WasmDecoder {
369 public: 369 public:
370 LR_WasmDecoder(Zone* zone, TFBuilder* builder) 370 SR_WasmDecoder(Zone* zone, TFBuilder* builder, FunctionBody& body)
371 : zone_(zone), 371 : WasmDecoder(body.module, body.sig, body.start, body.end),
372 zone_(zone),
372 builder_(builder), 373 builder_(builder),
374 base_(body.base),
375 local_type_vec_(zone),
373 trees_(zone), 376 trees_(zone),
374 stack_(zone), 377 stack_(zone),
375 blocks_(zone), 378 blocks_(zone),
376 ifs_(zone) {} 379 ifs_(zone) {
380 local_types_ = &local_type_vec_;
381 }
377 382
378 TreeResult Decode(FunctionEnv* function_env, const byte* base, const byte* pc, 383 TreeResult Decode() {
379 const byte* end) {
380 base::ElapsedTimer decode_timer; 384 base::ElapsedTimer decode_timer;
381 if (FLAG_trace_wasm_decode_time) { 385 if (FLAG_trace_wasm_decode_time) {
382 decode_timer.Start(); 386 decode_timer.Start();
383 } 387 }
384 trees_.clear();
385 stack_.clear();
386 blocks_.clear();
387 ifs_.clear();
388 388
389 if (end < pc) { 389 if (end_ < pc_) {
390 error(pc, "function body end < start"); 390 error(pc_, "function body end < start");
391 return result_; 391 return result_;
392 } 392 }
393 393
394 base_ = base; 394 DecodeLocalDecls();
395 Reset(function_env, pc, end);
396
397 InitSsaEnv(); 395 InitSsaEnv();
398 DecodeFunctionBody(); 396 DecodeFunctionBody();
399 397
400 Tree* tree = nullptr; 398 Tree* tree = nullptr;
401 if (ok()) { 399 if (ok()) {
402 if (ssa_env_->go()) { 400 if (ssa_env_->go()) {
403 if (stack_.size() > 0) { 401 if (stack_.size() > 0) {
404 error(stack_.back().pc(), end, "fell off end of code"); 402 error(stack_.back().pc(), end_, "fell off end of code");
405 } 403 }
406 AddImplicitReturnAtEnd(); 404 AddImplicitReturnAtEnd();
407 } 405 }
408 if (trees_.size() == 0) { 406 if (trees_.size() == 0) {
409 if (function_env_->sig->return_count() > 0) { 407 if (sig_->return_count() > 0) {
410 error(start_, "no trees created"); 408 error(start_, "no trees created");
411 } 409 }
412 } else { 410 } else {
413 tree = trees_[0]; 411 tree = trees_[0];
414 } 412 }
415 } 413 }
416 414
417 if (ok()) { 415 if (ok()) {
418 if (FLAG_trace_wasm_ast) { 416 if (FLAG_trace_wasm_ast) {
419 PrintAst(function_env, pc, end); 417 FunctionBody body = {module_, sig_, base_, start_, end_};
418 PrintAst(body);
420 } 419 }
421 if (FLAG_trace_wasm_decode_time) { 420 if (FLAG_trace_wasm_decode_time) {
422 double ms = decode_timer.Elapsed().InMillisecondsF(); 421 double ms = decode_timer.Elapsed().InMillisecondsF();
423 PrintF("wasm-decode ok (%0.3f ms)\n\n", ms); 422 PrintF("wasm-decode ok (%0.3f ms)\n\n", ms);
424 } else { 423 } else {
425 TRACE("wasm-decode ok\n\n"); 424 TRACE("wasm-decode ok\n\n");
426 } 425 }
427 } else { 426 } else {
428 TRACE("wasm-error module+%-6d func+%d: %s\n\n", baserel(error_pc_), 427 TRACE("wasm-error module+%-6d func+%d: %s\n\n", baserel(error_pc_),
429 startrel(error_pc_), error_msg_.get()); 428 startrel(error_pc_), error_msg_.get());
430 } 429 }
431 430
432 return toResult(tree); 431 return toResult(tree);
433 } 432 }
434 433
434 std::vector<LocalType>* DecodeLocalDeclsForTesting() {
435 DecodeLocalDecls();
436 if (failed()) return nullptr;
437 auto result = new std::vector<LocalType>();
438 result->reserve(local_type_vec_.size());
439 for (size_t i = 0; i < local_type_vec_.size(); i++) {
440 result->push_back(local_type_vec_[i]);
441 }
442 return result;
443 }
444
445 BitVector* AnalyzeLoopAssignmentForTesting(const byte* pc,
446 size_t num_locals) {
447 total_locals_ = num_locals;
448 local_type_vec_.reserve(num_locals);
449 if (num_locals > local_type_vec_.size()) {
450 local_type_vec_.insert(local_type_vec_.end(),
bradnelson 2016/03/02 21:51:15 Shame how big this gonna be, but oh well.
titzer 2016/03/02 22:43:41 It's only for testing, so, no big deal.
451 num_locals - local_type_vec_.size(), kAstI32);
452 }
453 return AnalyzeLoopAssignment(pc);
454 }
455
435 private: 456 private:
436 static const size_t kErrorMsgSize = 128; 457 static const size_t kErrorMsgSize = 128;
437 458
438 Zone* zone_; 459 Zone* zone_;
439 TFBuilder* builder_; 460 TFBuilder* builder_;
440 const byte* base_; 461 const byte* base_;
441 TreeResult result_; 462 TreeResult result_;
442 463
443 SsaEnv* ssa_env_; 464 SsaEnv* ssa_env_;
444 465
466 ZoneVector<LocalType> local_type_vec_;
445 ZoneVector<Tree*> trees_; 467 ZoneVector<Tree*> trees_;
446 ZoneVector<Production> stack_; 468 ZoneVector<Production> stack_;
447 ZoneVector<Block> blocks_; 469 ZoneVector<Block> blocks_;
448 ZoneVector<IfEnv> ifs_; 470 ZoneVector<IfEnv> ifs_;
449 471
450 inline bool build() { return builder_ && ssa_env_->go(); } 472 inline bool build() { return builder_ && ssa_env_->go(); }
451 473
452 void InitSsaEnv() { 474 void InitSsaEnv() {
453 FunctionSig* sig = function_env_->sig;
454 int param_count = static_cast<int>(sig->parameter_count());
455 TFNode* start = nullptr; 475 TFNode* start = nullptr;
456 SsaEnv* ssa_env = reinterpret_cast<SsaEnv*>(zone_->New(sizeof(SsaEnv))); 476 SsaEnv* ssa_env = reinterpret_cast<SsaEnv*>(zone_->New(sizeof(SsaEnv)));
457 size_t size = sizeof(TFNode*) * EnvironmentCount(); 477 size_t size = sizeof(TFNode*) * EnvironmentCount();
458 ssa_env->state = SsaEnv::kReached; 478 ssa_env->state = SsaEnv::kReached;
459 ssa_env->locals = 479 ssa_env->locals =
460 size > 0 ? reinterpret_cast<TFNode**>(zone_->New(size)) : nullptr; 480 size > 0 ? reinterpret_cast<TFNode**>(zone_->New(size)) : nullptr;
461 481
462 int pos = 0;
463 if (builder_) { 482 if (builder_) {
464 start = builder_->Start(param_count + 1); 483 start = builder_->Start(static_cast<int>(sig_->parameter_count() + 1));
465 // Initialize parameters. 484 // Initialize local variables.
466 for (int i = 0; i < param_count; i++) { 485 uint32_t index = 0;
467 ssa_env->locals[pos++] = builder_->Param(i, sig->GetParam(i)); 486 while (index < sig_->parameter_count()) {
487 ssa_env->locals[index] = builder_->Param(index, local_type_vec_[index]);
488 index++;
468 } 489 }
469 // Initialize int32 locals. 490 while (index < local_type_vec_.size()) {
470 if (function_env_->local_i32_count > 0) { 491 LocalType type = local_type_vec_[index];
471 TFNode* zero = builder_->Int32Constant(0); 492 TFNode* node = DefaultValue(type);
472 for (uint32_t i = 0; i < function_env_->local_i32_count; i++) { 493 while (index < local_type_vec_.size() &&
473 ssa_env->locals[pos++] = zero; 494 local_type_vec_[index] == type) {
495 // Do a whole run of like-typed locals at a time.
496 ssa_env->locals[index++] = node;
474 } 497 }
475 } 498 }
476 // Initialize int64 locals. 499 builder_->set_module(module_);
477 if (function_env_->local_i64_count > 0) {
478 TFNode* zero = builder_->Int64Constant(0);
479 for (uint32_t i = 0; i < function_env_->local_i64_count; i++) {
480 ssa_env->locals[pos++] = zero;
481 }
482 }
483 // Initialize float32 locals.
484 if (function_env_->local_f32_count > 0) {
485 TFNode* zero = builder_->Float32Constant(0);
486 for (uint32_t i = 0; i < function_env_->local_f32_count; i++) {
487 ssa_env->locals[pos++] = zero;
488 }
489 }
490 // Initialize float64 locals.
491 if (function_env_->local_f64_count > 0) {
492 TFNode* zero = builder_->Float64Constant(0);
493 for (uint32_t i = 0; i < function_env_->local_f64_count; i++) {
494 ssa_env->locals[pos++] = zero;
495 }
496 }
497 DCHECK_EQ(function_env_->total_locals, pos);
498 DCHECK_EQ(EnvironmentCount(), pos);
499 builder_->set_module(function_env_->module);
500 } 500 }
501 ssa_env->control = start; 501 ssa_env->control = start;
502 ssa_env->effect = start; 502 ssa_env->effect = start;
503 SetEnv("initial", ssa_env); 503 SetEnv("initial", ssa_env);
504 } 504 }
505 505
506 TFNode* DefaultValue(LocalType type) {
507 switch (type) {
508 case kAstI32:
509 return builder_->Int32Constant(0);
510 case kAstI64:
511 return builder_->Int64Constant(0);
512 case kAstF32:
513 return builder_->Float32Constant(0);
514 case kAstF64:
515 return builder_->Float64Constant(0);
516 default:
517 UNREACHABLE();
518 return nullptr;
519 }
520 }
521
506 void Leaf(LocalType type, TFNode* node = nullptr) { 522 void Leaf(LocalType type, TFNode* node = nullptr) {
507 size_t size = sizeof(Tree); 523 size_t size = sizeof(Tree);
508 Tree* tree = reinterpret_cast<Tree*>(zone_->New(size)); 524 Tree* tree = reinterpret_cast<Tree*>(zone_->New(size));
509 tree->type = type; 525 tree->type = type;
510 tree->count = 0; 526 tree->count = 0;
511 tree->pc = pc_; 527 tree->pc = pc_;
512 tree->node = node; 528 tree->node = node;
513 tree->children[0] = nullptr; 529 tree->children[0] = nullptr;
514 Reduce(tree); 530 Reduce(tree);
515 } 531 }
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
554 static const int kMaxIndent = 64; 570 static const int kMaxIndent = 64;
555 static char bytes[kMaxIndent + 1]; 571 static char bytes[kMaxIndent + 1];
556 for (int i = 0; i < kMaxIndent; i++) bytes[i] = ' '; 572 for (int i = 0; i < kMaxIndent; i++) bytes[i] = ' ';
557 bytes[kMaxIndent] = 0; 573 bytes[kMaxIndent] = 0;
558 if (stack_.size() < kMaxIndent / 2) { 574 if (stack_.size() < kMaxIndent / 2) {
559 bytes[stack_.size() * 2] = 0; 575 bytes[stack_.size() * 2] = 0;
560 } 576 }
561 return bytes; 577 return bytes;
562 } 578 }
563 579
580 // Decodes the locals declarations, if any, populating {local_type_vec_}.
581 void DecodeLocalDecls() {
582 DCHECK_EQ(0, local_type_vec_.size());
583 // Initialize {local_type_vec} from signature.
584 if (sig_) {
585 local_type_vec_.reserve(sig_->parameter_count());
586 for (size_t i = 0; i < sig_->parameter_count(); i++) {
587 local_type_vec_.push_back(sig_->GetParam(i));
588 }
589 }
590 // Decode local declarations, if any.
591 int length;
592 uint32_t entries = consume_u32v(&length, "local decls count");
593 while (entries-- > 0 && pc_ < limit_) {
594 uint32_t count = consume_u32v(&length, "local count");
595 byte code = consume_u8("local type");
596 LocalType type;
597 switch (code) {
598 case kLocalI32:
599 type = kAstI32;
600 break;
601 case kLocalI64:
602 type = kAstI64;
603 break;
604 case kLocalF32:
605 type = kAstF32;
606 break;
607 case kLocalF64:
608 type = kAstF64;
609 break;
610 default:
611 error(pc_ - 1, "invalid local type");
612 return;
613 }
614 local_type_vec_.insert(local_type_vec_.end(), count, type);
615 }
616 total_locals_ = local_type_vec_.size();
617 }
618
564 // Decodes the body of a function, producing reduced trees into {result}. 619 // Decodes the body of a function, producing reduced trees into {result}.
565 void DecodeFunctionBody() { 620 void DecodeFunctionBody() {
566 TRACE("wasm-decode %p...%p (%d bytes) %s\n", 621 TRACE("wasm-decode %p...%p (%d bytes) %s\n",
567 reinterpret_cast<const void*>(start_), 622 reinterpret_cast<const void*>(start_),
568 reinterpret_cast<const void*>(limit_), 623 reinterpret_cast<const void*>(limit_),
569 static_cast<int>(limit_ - start_), builder_ ? "graph building" : ""); 624 static_cast<int>(limit_ - start_), builder_ ? "graph building" : "");
570 625
571 if (pc_ >= limit_) return; // Nothing to do. 626 if (pc_ >= limit_) return; // Nothing to do.
572 627
573 while (true) { // decoding loop. 628 while (true) { // decoding loop.
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
657 } 712 }
658 case kExprTableSwitch: { 713 case kExprTableSwitch: {
659 TableSwitchOperand operand(this, pc_); 714 TableSwitchOperand operand(this, pc_);
660 if (Validate(pc_, operand, blocks_.size())) { 715 if (Validate(pc_, operand, blocks_.size())) {
661 Shift(kAstEnd, 1 + operand.case_count); 716 Shift(kAstEnd, 1 + operand.case_count);
662 } 717 }
663 len = 1 + operand.length; 718 len = 1 + operand.length;
664 break; 719 break;
665 } 720 }
666 case kExprReturn: { 721 case kExprReturn: {
667 int count = static_cast<int>(function_env_->sig->return_count()); 722 int count = static_cast<int>(sig_->return_count());
668 if (count == 0) { 723 if (count == 0) {
669 BUILD(Return, 0, builder_->Buffer(0)); 724 BUILD(Return, 0, builder_->Buffer(0));
670 ssa_env_->Kill(); 725 ssa_env_->Kill();
671 Leaf(kAstEnd); 726 Leaf(kAstEnd);
672 } else { 727 } else {
673 Shift(kAstEnd, count); 728 Shift(kAstEnd, count);
674 } 729 }
675 break; 730 break;
676 } 731 }
677 case kExprUnreachable: { 732 case kExprUnreachable: {
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after
814 ImportIndexOperand operand(this, pc_); 869 ImportIndexOperand operand(this, pc_);
815 if (Validate(pc_, operand)) { 870 if (Validate(pc_, operand)) {
816 LocalType type = operand.sig->return_count() == 0 871 LocalType type = operand.sig->return_count() == 0
817 ? kAstStmt 872 ? kAstStmt
818 : operand.sig->GetReturn(); 873 : operand.sig->GetReturn();
819 Shift(type, static_cast<int>(operand.sig->parameter_count())); 874 Shift(type, static_cast<int>(operand.sig->parameter_count()));
820 } 875 }
821 len = 1 + operand.length; 876 len = 1 + operand.length;
822 break; 877 break;
823 } 878 }
879 case kExprDeclLocals:
824 default: 880 default:
825 error("Invalid opcode"); 881 error("Invalid opcode");
826 return; 882 return;
827 } 883 }
828 pc_ += len; 884 pc_ += len;
829 if (pc_ >= limit_) { 885 if (pc_ >= limit_) {
830 // End of code reached or exceeded. 886 // End of code reached or exceeded.
831 if (pc_ > limit_ && ok()) { 887 if (pc_ > limit_ && ok()) {
832 error("Beyond end of code"); 888 error("Beyond end of code");
833 } 889 }
(...skipping 12 matching lines...) Expand all
846 return 1 + operand.length; 902 return 1 + operand.length;
847 } 903 }
848 904
849 int DecodeStoreMem(const byte* pc, LocalType type) { 905 int DecodeStoreMem(const byte* pc, LocalType type) {
850 MemoryAccessOperand operand(this, pc); 906 MemoryAccessOperand operand(this, pc);
851 Shift(type, 2); 907 Shift(type, 2);
852 return 1 + operand.length; 908 return 1 + operand.length;
853 } 909 }
854 910
855 void AddImplicitReturnAtEnd() { 911 void AddImplicitReturnAtEnd() {
856 int retcount = static_cast<int>(function_env_->sig->return_count()); 912 int retcount = static_cast<int>(sig_->return_count());
857 if (retcount == 0) { 913 if (retcount == 0) {
858 BUILD0(ReturnVoid); 914 BUILD0(ReturnVoid);
859 return; 915 return;
860 } 916 }
861 917
862 if (static_cast<int>(trees_.size()) < retcount) { 918 if (static_cast<int>(trees_.size()) < retcount) {
863 error(limit_, nullptr, 919 error(limit_, nullptr,
864 "ImplicitReturn expects %d arguments, only %d remain", retcount, 920 "ImplicitReturn expects %d arguments, only %d remain", retcount,
865 static_cast<int>(trees_.size())); 921 static_cast<int>(trees_.size()));
866 return; 922 return;
867 } 923 }
868 924
869 TRACE("wasm-decode implicit return of %d args\n", retcount); 925 TRACE("wasm-decode implicit return of %d args\n", retcount);
870 926
871 TFNode** buffer = BUILD(Buffer, retcount); 927 TFNode** buffer = BUILD(Buffer, retcount);
872 for (int index = 0; index < retcount; index++) { 928 for (int index = 0; index < retcount; index++) {
873 Tree* tree = trees_[trees_.size() - 1 - index]; 929 Tree* tree = trees_[trees_.size() - 1 - index];
874 if (buffer) buffer[index] = tree->node; 930 if (buffer) buffer[index] = tree->node;
875 LocalType expected = function_env_->sig->GetReturn(index); 931 LocalType expected = sig_->GetReturn(index);
876 if (tree->type != expected) { 932 if (tree->type != expected) {
877 error(limit_, tree->pc, 933 error(limit_, tree->pc,
878 "ImplicitReturn[%d] expected type %s, found %s of type %s", index, 934 "ImplicitReturn[%d] expected type %s, found %s of type %s", index,
879 WasmOpcodes::TypeName(expected), 935 WasmOpcodes::TypeName(expected),
880 WasmOpcodes::OpcodeName(tree->opcode()), 936 WasmOpcodes::OpcodeName(tree->opcode()),
881 WasmOpcodes::TypeName(tree->type)); 937 WasmOpcodes::TypeName(tree->type));
882 return; 938 return;
883 } 939 }
884 } 940 }
885 941
(...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after
1102 SetEnv("switch:end", next); 1158 SetEnv("switch:end", next);
1103 } else { 1159 } else {
1104 // Interior case. Maybe fall through to the next case. 1160 // Interior case. Maybe fall through to the next case.
1105 SsaEnv* next = ifs_.back().case_envs[p->index - 1]; 1161 SsaEnv* next = ifs_.back().case_envs[p->index - 1];
1106 if (p->index > 1 && ssa_env_->go()) Goto(ssa_env_, next); 1162 if (p->index > 1 && ssa_env_->go()) Goto(ssa_env_, next);
1107 SetEnv("switch:case", next); 1163 SetEnv("switch:case", next);
1108 } 1164 }
1109 break; 1165 break;
1110 } 1166 }
1111 case kExprReturn: { 1167 case kExprReturn: {
1112 TypeCheckLast(p, function_env_->sig->GetReturn(p->index - 1)); 1168 TypeCheckLast(p, sig_->GetReturn(p->index - 1));
1113 if (p->done()) { 1169 if (p->done()) {
1114 if (build()) { 1170 if (build()) {
1115 int count = p->tree->count; 1171 int count = p->tree->count;
1116 TFNode** buffer = builder_->Buffer(count); 1172 TFNode** buffer = builder_->Buffer(count);
1117 for (int i = 0; i < count; i++) { 1173 for (int i = 0; i < count; i++) {
1118 buffer[i] = p->tree->children[i]->node; 1174 buffer[i] = p->tree->children[i]->node;
1119 } 1175 }
1120 BUILD(Return, count, buffer); 1176 BUILD(Return, count, buffer);
1121 } 1177 }
1122 ssa_env_->Kill(SsaEnv::kControlEnd); 1178 ssa_env_->Kill(SsaEnv::kControlEnd);
(...skipping 259 matching lines...) Expand 10 before | Expand all | Expand 10 after
1382 if (from->effect != to->effect) { 1438 if (from->effect != to->effect) {
1383 TFNode* effects[] = {to->effect, from->effect, merge}; 1439 TFNode* effects[] = {to->effect, from->effect, merge};
1384 to->effect = builder_->EffectPhi(2, effects, merge); 1440 to->effect = builder_->EffectPhi(2, effects, merge);
1385 } 1441 }
1386 // Merge SSA values. 1442 // Merge SSA values.
1387 for (int i = EnvironmentCount() - 1; i >= 0; i--) { 1443 for (int i = EnvironmentCount() - 1; i >= 0; i--) {
1388 TFNode* a = to->locals[i]; 1444 TFNode* a = to->locals[i];
1389 TFNode* b = from->locals[i]; 1445 TFNode* b = from->locals[i];
1390 if (a != b) { 1446 if (a != b) {
1391 TFNode* vals[] = {a, b}; 1447 TFNode* vals[] = {a, b};
1392 to->locals[i] = 1448 to->locals[i] = builder_->Phi(local_type_vec_[i], 2, vals, merge);
1393 builder_->Phi(function_env_->GetLocalType(i), 2, vals, merge);
1394 } 1449 }
1395 } 1450 }
1396 break; 1451 break;
1397 } 1452 }
1398 case SsaEnv::kMerged: { 1453 case SsaEnv::kMerged: {
1399 if (!builder_) break; 1454 if (!builder_) break;
1400 TFNode* merge = to->control; 1455 TFNode* merge = to->control;
1401 // Extend the existing merge. 1456 // Extend the existing merge.
1402 builder_->AppendToMerge(merge, from->control); 1457 builder_->AppendToMerge(merge, from->control);
1403 // Merge effects. 1458 // Merge effects.
(...skipping 14 matching lines...) Expand all
1418 TFNode* fnode = from->locals[i]; 1473 TFNode* fnode = from->locals[i];
1419 if (builder_->IsPhiWithMerge(tnode, merge)) { 1474 if (builder_->IsPhiWithMerge(tnode, merge)) {
1420 builder_->AppendToPhi(merge, tnode, fnode); 1475 builder_->AppendToPhi(merge, tnode, fnode);
1421 } else if (tnode != fnode) { 1476 } else if (tnode != fnode) {
1422 uint32_t count = builder_->InputCount(merge); 1477 uint32_t count = builder_->InputCount(merge);
1423 TFNode** vals = builder_->Buffer(count); 1478 TFNode** vals = builder_->Buffer(count);
1424 for (uint32_t j = 0; j < count - 1; j++) { 1479 for (uint32_t j = 0; j < count - 1; j++) {
1425 vals[j] = tnode; 1480 vals[j] = tnode;
1426 } 1481 }
1427 vals[count - 1] = fnode; 1482 vals[count - 1] = fnode;
1428 to->locals[i] = builder_->Phi(function_env_->GetLocalType(i), count, 1483 to->locals[i] =
1429 vals, merge); 1484 builder_->Phi(local_type_vec_[i], count, vals, merge);
1430 } 1485 }
1431 } 1486 }
1432 break; 1487 break;
1433 } 1488 }
1434 default: 1489 default:
1435 UNREACHABLE(); 1490 UNREACHABLE();
1436 } 1491 }
1437 return from->Kill(); 1492 return from->Kill();
1438 } 1493 }
1439 1494
(...skipping 22 matching lines...) Expand all
1462 } 1517 }
1463 1518
1464 void PrepareForLoop(SsaEnv* env) { 1519 void PrepareForLoop(SsaEnv* env) {
1465 if (env->go()) { 1520 if (env->go()) {
1466 env->state = SsaEnv::kMerged; 1521 env->state = SsaEnv::kMerged;
1467 if (builder_) { 1522 if (builder_) {
1468 env->control = builder_->Loop(env->control); 1523 env->control = builder_->Loop(env->control);
1469 env->effect = builder_->EffectPhi(1, &env->effect, env->control); 1524 env->effect = builder_->EffectPhi(1, &env->effect, env->control);
1470 builder_->Terminate(env->effect, env->control); 1525 builder_->Terminate(env->effect, env->control);
1471 for (int i = EnvironmentCount() - 1; i >= 0; i--) { 1526 for (int i = EnvironmentCount() - 1; i >= 0; i--) {
1472 env->locals[i] = builder_->Phi(function_env_->GetLocalType(i), 1, 1527 env->locals[i] = builder_->Phi(local_type_vec_[i], 1, &env->locals[i],
1473 &env->locals[i], env->control); 1528 env->control);
1474 } 1529 }
1475 } 1530 }
1476 } 1531 }
1477 } 1532 }
1478 1533
1479 // Create a complete copy of the {from}. 1534 // Create a complete copy of the {from}.
1480 SsaEnv* Split(SsaEnv* from) { 1535 SsaEnv* Split(SsaEnv* from) {
1481 DCHECK_NOT_NULL(from); 1536 DCHECK_NOT_NULL(from);
1482 SsaEnv* result = reinterpret_cast<SsaEnv*>(zone_->New(sizeof(SsaEnv))); 1537 SsaEnv* result = reinterpret_cast<SsaEnv*>(zone_->New(sizeof(SsaEnv)));
1483 size_t size = sizeof(TFNode*) * EnvironmentCount(); 1538 size_t size = sizeof(TFNode*) * EnvironmentCount();
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
1517 SsaEnv* UnreachableEnv() { 1572 SsaEnv* UnreachableEnv() {
1518 SsaEnv* result = reinterpret_cast<SsaEnv*>(zone_->New(sizeof(SsaEnv))); 1573 SsaEnv* result = reinterpret_cast<SsaEnv*>(zone_->New(sizeof(SsaEnv)));
1519 result->state = SsaEnv::kUnreachable; 1574 result->state = SsaEnv::kUnreachable;
1520 result->control = nullptr; 1575 result->control = nullptr;
1521 result->effect = nullptr; 1576 result->effect = nullptr;
1522 result->locals = nullptr; 1577 result->locals = nullptr;
1523 return result; 1578 return result;
1524 } 1579 }
1525 1580
1526 int EnvironmentCount() { 1581 int EnvironmentCount() {
1527 if (builder_) return static_cast<int>(function_env_->GetLocalCount()); 1582 if (builder_) return static_cast<int>(local_type_vec_.size());
1528 return 0; // if we aren't building a graph, don't bother with SSA renaming. 1583 return 0; // if we aren't building a graph, don't bother with SSA renaming.
1529 } 1584 }
1530 1585
1531 virtual void onFirstError() { 1586 virtual void onFirstError() {
1532 limit_ = start_; // Terminate decoding loop. 1587 limit_ = start_; // Terminate decoding loop.
1533 builder_ = nullptr; // Don't build any more nodes. 1588 builder_ = nullptr; // Don't build any more nodes.
1534 #if DEBUG 1589 #if DEBUG
1535 PrintStackForDebugging(); 1590 PrintStackForDebugging();
1536 #endif 1591 #endif
1537 } 1592 }
(...skipping 15 matching lines...) Expand all
1553 WasmOpcodes::OpcodeName(child->opcode()), child->count); 1608 WasmOpcodes::OpcodeName(child->opcode()), child->count);
1554 if (child->node) { 1609 if (child->node) {
1555 PrintF(" => TF"); 1610 PrintF(" => TF");
1556 compiler::WasmGraphBuilder::PrintDebugName(child->node); 1611 compiler::WasmGraphBuilder::PrintDebugName(child->node);
1557 } 1612 }
1558 PrintF("\n"); 1613 PrintF("\n");
1559 } 1614 }
1560 PrintProduction(depth + 1); 1615 PrintProduction(depth + 1);
1561 } 1616 }
1562 #endif 1617 #endif
1618
1619 BitVector* AnalyzeLoopAssignment(const byte* pc) {
1620 if (pc >= limit_) return nullptr;
1621 if (*pc != kExprLoop) return nullptr;
1622
1623 BitVector* assigned =
1624 new (zone_) BitVector(static_cast<int>(total_locals_), zone_);
1625 // Keep a stack to model the nesting of expressions.
1626 std::vector<int> arity_stack;
1627 arity_stack.push_back(OpcodeArity(pc));
1628 pc += OpcodeLength(pc);
1629
1630 // Iteratively process all AST nodes nested inside the loop.
1631 while (pc < limit_) {
1632 WasmOpcode opcode = static_cast<WasmOpcode>(*pc);
1633 int arity = 0;
1634 int length = 1;
1635 if (opcode == kExprSetLocal) {
1636 LocalIndexOperand operand(this, pc);
1637 if (assigned->length() > 0 &&
1638 static_cast<int>(operand.index) < assigned->length()) {
1639 // Unverified code might have an out-of-bounds index.
1640 assigned->Add(operand.index);
1641 }
1642 arity = 1;
1643 length = 1 + operand.length;
1644 } else {
1645 arity = OpcodeArity(pc);
1646 length = OpcodeLength(pc);
1647 }
1648
1649 pc += length;
1650 arity_stack.push_back(arity);
1651 while (arity_stack.back() == 0) {
1652 arity_stack.pop_back();
1653 if (arity_stack.empty()) return assigned; // reached end of loop
1654 arity_stack.back()--;
1655 }
1656 }
1657 return assigned;
1658 }
1563 }; 1659 };
1564 1660
1661 std::vector<LocalType>* DecodeLocalDeclsForTesting(const byte* start,
1662 const byte* end) {
1663 Zone zone;
1664 FunctionBody body = {nullptr, nullptr, nullptr, start, end};
1665 SR_WasmDecoder decoder(&zone, nullptr, body);
1666 return decoder.DecodeLocalDeclsForTesting();
1667 }
1565 1668
1566 TreeResult VerifyWasmCode(FunctionEnv* env, const byte* base, const byte* start, 1669 TreeResult VerifyWasmCode(FunctionBody& body) {
1567 const byte* end) {
1568 Zone zone; 1670 Zone zone;
1569 LR_WasmDecoder decoder(&zone, nullptr); 1671 SR_WasmDecoder decoder(&zone, nullptr, body);
1570 TreeResult result = decoder.Decode(env, base, start, end); 1672 TreeResult result = decoder.Decode();
1571 return result; 1673 return result;
1572 } 1674 }
1573 1675
1574 1676 TreeResult BuildTFGraph(TFBuilder* builder, FunctionBody& body) {
1575 TreeResult BuildTFGraph(TFBuilder* builder, FunctionEnv* env, const byte* base,
1576 const byte* start, const byte* end) {
1577 Zone zone; 1677 Zone zone;
1578 LR_WasmDecoder decoder(&zone, builder); 1678 SR_WasmDecoder decoder(&zone, builder, body);
1579 TreeResult result = decoder.Decode(env, base, start, end); 1679 TreeResult result = decoder.Decode();
1580 return result; 1680 return result;
1581 } 1681 }
1582 1682
1583 1683
1584 std::ostream& operator<<(std::ostream& os, const Tree& tree) { 1684 std::ostream& operator<<(std::ostream& os, const Tree& tree) {
1585 if (tree.pc == nullptr) { 1685 if (tree.pc == nullptr) {
1586 os << "null"; 1686 os << "null";
1587 return os; 1687 return os;
1588 } 1688 }
1589 PrintF("%s", WasmOpcodes::OpcodeName(tree.opcode())); 1689 PrintF("%s", WasmOpcodes::OpcodeName(tree.opcode()));
(...skipping 11 matching lines...) Expand all
1601 const byte* limit, 1701 const byte* limit,
1602 int* length, 1702 int* length,
1603 uint32_t* result) { 1703 uint32_t* result) {
1604 Decoder decoder(pc, limit); 1704 Decoder decoder(pc, limit);
1605 *result = decoder.checked_read_u32v(pc, 0, length); 1705 *result = decoder.checked_read_u32v(pc, 0, length);
1606 if (decoder.ok()) return kNoError; 1706 if (decoder.ok()) return kNoError;
1607 return (limit - pc) > 1 ? kInvalidLEB128 : kMissingLEB128; 1707 return (limit - pc) > 1 ? kInvalidLEB128 : kMissingLEB128;
1608 } 1708 }
1609 1709
1610 int OpcodeLength(const byte* pc, const byte* end) { 1710 int OpcodeLength(const byte* pc, const byte* end) {
1611 WasmDecoder decoder(nullptr, pc, end); 1711 WasmDecoder decoder(nullptr, nullptr, pc, end);
1612 return decoder.OpcodeLength(pc); 1712 return decoder.OpcodeLength(pc);
1613 } 1713 }
1614 1714
1615 int OpcodeArity(FunctionEnv* env, const byte* pc, const byte* end) { 1715 int OpcodeArity(ModuleEnv* module, FunctionSig* sig, const byte* pc,
1616 WasmDecoder decoder(env, pc, end); 1716 const byte* end) {
1717 WasmDecoder decoder(module, sig, pc, end);
1617 return decoder.OpcodeArity(pc); 1718 return decoder.OpcodeArity(pc);
1618 } 1719 }
1619 1720
1620 void PrintAst(FunctionEnv* env, const byte* start, const byte* end) { 1721 void PrintAst(FunctionBody& body) {
1621 WasmDecoder decoder(env, start, end); 1722 WasmDecoder decoder(body.module, body.sig, body.start, body.end);
1622 const byte* pc = start; 1723 const byte* pc = body.start;
1623 std::vector<int> arity_stack; 1724 std::vector<int> arity_stack;
1624 while (pc < end) { 1725 while (pc < body.end) {
1625 int arity = decoder.OpcodeArity(pc); 1726 int arity = decoder.OpcodeArity(pc);
1626 size_t length = decoder.OpcodeLength(pc); 1727 size_t length = decoder.OpcodeLength(pc);
1627 1728
1628 for (auto arity : arity_stack) { 1729 for (auto arity : arity_stack) {
1629 printf(" "); 1730 printf(" ");
1630 USE(arity); 1731 USE(arity);
1631 } 1732 }
1632 1733
1633 WasmOpcode opcode = static_cast<WasmOpcode>(*pc); 1734 WasmOpcode opcode = static_cast<WasmOpcode>(*pc);
1634 printf("k%s,", WasmOpcodes::OpcodeName(opcode)); 1735 printf("k%s,", WasmOpcodes::OpcodeName(opcode));
1635 1736
1636 for (size_t i = 1; i < length; i++) { 1737 for (size_t i = 1; i < length; i++) {
1637 printf(" 0x%02x,", pc[i]); 1738 printf(" 0x%02x,", pc[i]);
1638 } 1739 }
1639 pc += length; 1740 pc += length;
1640 printf("\n"); 1741 printf("\n");
1641 1742
1642 arity_stack.push_back(arity); 1743 arity_stack.push_back(arity);
1643 while (arity_stack.back() == 0) { 1744 while (arity_stack.back() == 0) {
1644 arity_stack.pop_back(); 1745 arity_stack.pop_back();
1645 if (arity_stack.empty()) break; 1746 if (arity_stack.empty()) break;
1646 arity_stack.back()--; 1747 arity_stack.back()--;
1647 } 1748 }
1648 } 1749 }
1649 } 1750 }
1650 1751
1651 // Analyzes loop bodies for static assignments to locals, which helps in 1752 BitVector* AnalyzeLoopAssignmentForTesting(Zone* zone, size_t num_locals,
1652 // reducing the number of phis introduced at loop headers.
1653 class LoopAssignmentAnalyzer : public WasmDecoder {
1654 public:
1655 LoopAssignmentAnalyzer(Zone* zone, FunctionEnv* function_env) : zone_(zone) {
1656 function_env_ = function_env;
1657 }
1658
1659 BitVector* Analyze(const byte* pc, const byte* limit) {
1660 Decoder::Reset(pc, limit);
1661 if (pc_ >= limit_) return nullptr;
1662 if (*pc_ != kExprLoop) return nullptr;
1663
1664 BitVector* assigned =
1665 new (zone_) BitVector(function_env_->total_locals, zone_);
1666 // Keep a stack to model the nesting of expressions.
1667 std::vector<int> arity_stack;
1668 arity_stack.push_back(OpcodeArity(pc_));
1669 pc_ += OpcodeLength(pc_);
1670
1671 // Iteratively process all AST nodes nested inside the loop.
1672 while (pc_ < limit_) {
1673 WasmOpcode opcode = static_cast<WasmOpcode>(*pc_);
1674 int arity = 0;
1675 int length = 1;
1676 if (opcode == kExprSetLocal) {
1677 LocalIndexOperand operand(this, pc_);
1678 if (assigned->length() > 0 &&
1679 static_cast<int>(operand.index) < assigned->length()) {
1680 // Unverified code might have an out-of-bounds index.
1681 assigned->Add(operand.index);
1682 }
1683 arity = 1;
1684 length = 1 + operand.length;
1685 } else {
1686 arity = OpcodeArity(pc_);
1687 length = OpcodeLength(pc_);
1688 }
1689
1690 pc_ += length;
1691 arity_stack.push_back(arity);
1692 while (arity_stack.back() == 0) {
1693 arity_stack.pop_back();
1694 if (arity_stack.empty()) return assigned; // reached end of loop
1695 arity_stack.back()--;
1696 }
1697 }
1698 return assigned;
1699 }
1700
1701 private:
1702 Zone* zone_;
1703 };
1704
1705
1706 BitVector* AnalyzeLoopAssignmentForTesting(Zone* zone, FunctionEnv* env,
1707 const byte* start, const byte* end) { 1753 const byte* start, const byte* end) {
1708 LoopAssignmentAnalyzer analyzer(zone, env); 1754 FunctionBody body = {nullptr, nullptr, nullptr, start, end};
1709 return analyzer.Analyze(start, end); 1755 SR_WasmDecoder decoder(zone, nullptr, body);
1756 return decoder.AnalyzeLoopAssignmentForTesting(start, num_locals);
1710 } 1757 }
1711 1758
1712 } // namespace wasm 1759 } // namespace wasm
1713 } // namespace internal 1760 } // namespace internal
1714 } // namespace v8 1761 } // namespace v8
OLDNEW
« no previous file with comments | « src/wasm/ast-decoder.h ('k') | src/wasm/decoder.h » ('j') | src/wasm/encoder.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698