OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |