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 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
243 | 244 |
244 case kExprBlock: | 245 case kExprBlock: |
245 case kExprLoop: { | 246 case kExprLoop: { |
246 BlockCountOperand operand(this, pc); | 247 BlockCountOperand operand(this, pc); |
247 return operand.count; | 248 return operand.count; |
248 } | 249 } |
249 | 250 |
250 case kExprCallFunction: { | 251 case kExprCallFunction: { |
251 FunctionIndexOperand operand(this, pc); | 252 FunctionIndexOperand operand(this, pc); |
252 return static_cast<int>( | 253 return static_cast<int>( |
253 function_env_->module->GetFunctionSignature(operand.index) | 254 module_->GetFunctionSignature(operand.index)->parameter_count()); |
254 ->parameter_count()); | |
255 } | 255 } |
256 case kExprCallIndirect: { | 256 case kExprCallIndirect: { |
257 SignatureIndexOperand operand(this, pc); | 257 SignatureIndexOperand operand(this, pc); |
258 return 1 + static_cast<int>( | 258 return 1 + static_cast<int>( |
259 function_env_->module->GetSignature(operand.index) | 259 module_->GetSignature(operand.index)->parameter_count()); |
260 ->parameter_count()); | |
261 } | 260 } |
262 case kExprCallImport: { | 261 case kExprCallImport: { |
263 ImportIndexOperand operand(this, pc); | 262 ImportIndexOperand operand(this, pc); |
264 return static_cast<int>( | 263 return static_cast<int>( |
265 function_env_->module->GetImportSignature(operand.index) | 264 module_->GetImportSignature(operand.index)->parameter_count()); |
266 ->parameter_count()); | |
267 } | 265 } |
268 case kExprReturn: { | 266 case kExprReturn: { |
269 return static_cast<int>(function_env_->sig->return_count()); | 267 return static_cast<int>(sig_->return_count()); |
270 } | 268 } |
271 case kExprBrTable: { | 269 case kExprBrTable: { |
272 return 1; | 270 return 1; |
273 } | 271 } |
274 | 272 |
275 #define DECLARE_OPCODE_CASE(name, opcode, sig) \ | 273 #define DECLARE_OPCODE_CASE(name, opcode, sig) \ |
276 case kExpr##name: \ | 274 case kExpr##name: \ |
277 return kArity_##sig; | 275 return kArity_##sig; |
278 | 276 |
279 FOREACH_LOAD_MEM_OPCODE(DECLARE_OPCODE_CASE) | 277 FOREACH_LOAD_MEM_OPCODE(DECLARE_OPCODE_CASE) |
280 FOREACH_STORE_MEM_OPCODE(DECLARE_OPCODE_CASE) | 278 FOREACH_STORE_MEM_OPCODE(DECLARE_OPCODE_CASE) |
281 FOREACH_MISC_MEM_OPCODE(DECLARE_OPCODE_CASE) | 279 FOREACH_MISC_MEM_OPCODE(DECLARE_OPCODE_CASE) |
282 FOREACH_SIMPLE_OPCODE(DECLARE_OPCODE_CASE) | 280 FOREACH_SIMPLE_OPCODE(DECLARE_OPCODE_CASE) |
283 FOREACH_ASMJS_COMPAT_OPCODE(DECLARE_OPCODE_CASE) | 281 FOREACH_ASMJS_COMPAT_OPCODE(DECLARE_OPCODE_CASE) |
284 #undef DECLARE_OPCODE_CASE | 282 #undef DECLARE_OPCODE_CASE |
| 283 case kExprDeclLocals: |
| 284 default: |
| 285 UNREACHABLE(); |
| 286 return 0; |
285 } | 287 } |
286 UNREACHABLE(); | |
287 return 0; | |
288 } | 288 } |
289 | 289 |
290 int OpcodeLength(const byte* pc) { | 290 int OpcodeLength(const byte* pc) { |
291 switch (static_cast<WasmOpcode>(*pc)) { | 291 switch (static_cast<WasmOpcode>(*pc)) { |
292 #define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name: | 292 #define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name: |
293 FOREACH_LOAD_MEM_OPCODE(DECLARE_OPCODE_CASE) | 293 FOREACH_LOAD_MEM_OPCODE(DECLARE_OPCODE_CASE) |
294 FOREACH_STORE_MEM_OPCODE(DECLARE_OPCODE_CASE) | 294 FOREACH_STORE_MEM_OPCODE(DECLARE_OPCODE_CASE) |
295 #undef DECLARE_OPCODE_CASE | 295 #undef DECLARE_OPCODE_CASE |
296 { | 296 { |
297 MemoryAccessOperand operand(this, pc); | 297 MemoryAccessOperand operand(this, pc); |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
346 | 346 |
347 default: | 347 default: |
348 return 1; | 348 return 1; |
349 } | 349 } |
350 } | 350 } |
351 }; | 351 }; |
352 | 352 |
353 | 353 |
354 // A shift-reduce-parser strategy for decoding Wasm code that uses an explicit | 354 // A shift-reduce-parser strategy for decoding Wasm code that uses an explicit |
355 // shift-reduce strategy with multiple internal stacks. | 355 // shift-reduce strategy with multiple internal stacks. |
356 class LR_WasmDecoder : public WasmDecoder { | 356 class SR_WasmDecoder : public WasmDecoder { |
357 public: | 357 public: |
358 LR_WasmDecoder(Zone* zone, TFBuilder* builder) | 358 SR_WasmDecoder(Zone* zone, TFBuilder* builder, FunctionBody& body) |
359 : zone_(zone), | 359 : WasmDecoder(body.module, body.sig, body.start, body.end), |
| 360 zone_(zone), |
360 builder_(builder), | 361 builder_(builder), |
| 362 base_(body.base), |
| 363 local_type_vec_(zone), |
361 trees_(zone), | 364 trees_(zone), |
362 stack_(zone), | 365 stack_(zone), |
363 blocks_(zone), | 366 blocks_(zone), |
364 ifs_(zone) {} | 367 ifs_(zone) { |
| 368 local_types_ = &local_type_vec_; |
| 369 } |
365 | 370 |
366 TreeResult Decode(FunctionEnv* function_env, const byte* base, const byte* pc, | 371 TreeResult Decode() { |
367 const byte* end) { | |
368 base::ElapsedTimer decode_timer; | 372 base::ElapsedTimer decode_timer; |
369 if (FLAG_trace_wasm_decode_time) { | 373 if (FLAG_trace_wasm_decode_time) { |
370 decode_timer.Start(); | 374 decode_timer.Start(); |
371 } | 375 } |
372 trees_.clear(); | |
373 stack_.clear(); | |
374 blocks_.clear(); | |
375 ifs_.clear(); | |
376 | 376 |
377 if (end < pc) { | 377 if (end_ < pc_) { |
378 error(pc, "function body end < start"); | 378 error(pc_, "function body end < start"); |
379 return result_; | 379 return result_; |
380 } | 380 } |
381 | 381 |
382 base_ = base; | 382 DecodeLocalDecls(); |
383 Reset(function_env, pc, end); | |
384 | |
385 InitSsaEnv(); | 383 InitSsaEnv(); |
386 DecodeFunctionBody(); | 384 DecodeFunctionBody(); |
387 | 385 |
388 Tree* tree = nullptr; | 386 Tree* tree = nullptr; |
389 if (ok()) { | 387 if (ok()) { |
390 if (ssa_env_->go()) { | 388 if (ssa_env_->go()) { |
391 if (stack_.size() > 0) { | 389 if (stack_.size() > 0) { |
392 error(stack_.back().pc(), end, "fell off end of code"); | 390 error(stack_.back().pc(), end_, "fell off end of code"); |
393 } | 391 } |
394 AddImplicitReturnAtEnd(); | 392 AddImplicitReturnAtEnd(); |
395 } | 393 } |
396 if (trees_.size() == 0) { | 394 if (trees_.size() == 0) { |
397 if (function_env_->sig->return_count() > 0) { | 395 if (sig_->return_count() > 0) { |
398 error(start_, "no trees created"); | 396 error(start_, "no trees created"); |
399 } | 397 } |
400 } else { | 398 } else { |
401 tree = trees_[0]; | 399 tree = trees_[0]; |
402 } | 400 } |
403 } | 401 } |
404 | 402 |
405 if (ok()) { | 403 if (ok()) { |
406 if (FLAG_trace_wasm_ast) { | 404 if (FLAG_trace_wasm_ast) { |
407 PrintAst(function_env, pc, end); | 405 FunctionBody body = {module_, sig_, base_, start_, end_}; |
| 406 PrintAst(body); |
408 } | 407 } |
409 if (FLAG_trace_wasm_decode_time) { | 408 if (FLAG_trace_wasm_decode_time) { |
410 double ms = decode_timer.Elapsed().InMillisecondsF(); | 409 double ms = decode_timer.Elapsed().InMillisecondsF(); |
411 PrintF("wasm-decode ok (%0.3f ms)\n\n", ms); | 410 PrintF("wasm-decode ok (%0.3f ms)\n\n", ms); |
412 } else { | 411 } else { |
413 TRACE("wasm-decode ok\n\n"); | 412 TRACE("wasm-decode ok\n\n"); |
414 } | 413 } |
415 } else { | 414 } else { |
416 TRACE("wasm-error module+%-6d func+%d: %s\n\n", baserel(error_pc_), | 415 TRACE("wasm-error module+%-6d func+%d: %s\n\n", baserel(error_pc_), |
417 startrel(error_pc_), error_msg_.get()); | 416 startrel(error_pc_), error_msg_.get()); |
418 } | 417 } |
419 | 418 |
420 return toResult(tree); | 419 return toResult(tree); |
421 } | 420 } |
422 | 421 |
| 422 std::vector<LocalType>* DecodeLocalDeclsForTesting() { |
| 423 DecodeLocalDecls(); |
| 424 if (failed()) return nullptr; |
| 425 auto result = new std::vector<LocalType>(); |
| 426 result->reserve(local_type_vec_.size()); |
| 427 for (size_t i = 0; i < local_type_vec_.size(); i++) { |
| 428 result->push_back(local_type_vec_[i]); |
| 429 } |
| 430 return result; |
| 431 } |
| 432 |
| 433 BitVector* AnalyzeLoopAssignmentForTesting(const byte* pc, |
| 434 size_t num_locals) { |
| 435 total_locals_ = num_locals; |
| 436 local_type_vec_.reserve(num_locals); |
| 437 if (num_locals > local_type_vec_.size()) { |
| 438 local_type_vec_.insert(local_type_vec_.end(), |
| 439 num_locals - local_type_vec_.size(), kAstI32); |
| 440 } |
| 441 return AnalyzeLoopAssignment(pc); |
| 442 } |
| 443 |
423 private: | 444 private: |
424 static const size_t kErrorMsgSize = 128; | 445 static const size_t kErrorMsgSize = 128; |
425 | 446 |
426 Zone* zone_; | 447 Zone* zone_; |
427 TFBuilder* builder_; | 448 TFBuilder* builder_; |
428 const byte* base_; | 449 const byte* base_; |
429 TreeResult result_; | 450 TreeResult result_; |
430 | 451 |
431 SsaEnv* ssa_env_; | 452 SsaEnv* ssa_env_; |
432 | 453 |
| 454 ZoneVector<LocalType> local_type_vec_; |
433 ZoneVector<Tree*> trees_; | 455 ZoneVector<Tree*> trees_; |
434 ZoneVector<Production> stack_; | 456 ZoneVector<Production> stack_; |
435 ZoneVector<Block> blocks_; | 457 ZoneVector<Block> blocks_; |
436 ZoneVector<IfEnv> ifs_; | 458 ZoneVector<IfEnv> ifs_; |
437 | 459 |
438 inline bool build() { return builder_ && ssa_env_->go(); } | 460 inline bool build() { return builder_ && ssa_env_->go(); } |
439 | 461 |
440 void InitSsaEnv() { | 462 void InitSsaEnv() { |
441 FunctionSig* sig = function_env_->sig; | |
442 int param_count = static_cast<int>(sig->parameter_count()); | |
443 TFNode* start = nullptr; | 463 TFNode* start = nullptr; |
444 SsaEnv* ssa_env = reinterpret_cast<SsaEnv*>(zone_->New(sizeof(SsaEnv))); | 464 SsaEnv* ssa_env = reinterpret_cast<SsaEnv*>(zone_->New(sizeof(SsaEnv))); |
445 size_t size = sizeof(TFNode*) * EnvironmentCount(); | 465 size_t size = sizeof(TFNode*) * EnvironmentCount(); |
446 ssa_env->state = SsaEnv::kReached; | 466 ssa_env->state = SsaEnv::kReached; |
447 ssa_env->locals = | 467 ssa_env->locals = |
448 size > 0 ? reinterpret_cast<TFNode**>(zone_->New(size)) : nullptr; | 468 size > 0 ? reinterpret_cast<TFNode**>(zone_->New(size)) : nullptr; |
449 | 469 |
450 int pos = 0; | |
451 if (builder_) { | 470 if (builder_) { |
452 start = builder_->Start(param_count + 1); | 471 start = builder_->Start(static_cast<int>(sig_->parameter_count() + 1)); |
453 // Initialize parameters. | 472 // Initialize local variables. |
454 for (int i = 0; i < param_count; i++) { | 473 uint32_t index = 0; |
455 ssa_env->locals[pos++] = builder_->Param(i, sig->GetParam(i)); | 474 while (index < sig_->parameter_count()) { |
| 475 ssa_env->locals[index] = builder_->Param(index, local_type_vec_[index]); |
| 476 index++; |
456 } | 477 } |
457 // Initialize int32 locals. | 478 while (index < local_type_vec_.size()) { |
458 if (function_env_->local_i32_count > 0) { | 479 LocalType type = local_type_vec_[index]; |
459 TFNode* zero = builder_->Int32Constant(0); | 480 TFNode* node = DefaultValue(type); |
460 for (uint32_t i = 0; i < function_env_->local_i32_count; i++) { | 481 while (index < local_type_vec_.size() && |
461 ssa_env->locals[pos++] = zero; | 482 local_type_vec_[index] == type) { |
| 483 // Do a whole run of like-typed locals at a time. |
| 484 ssa_env->locals[index++] = node; |
462 } | 485 } |
463 } | 486 } |
464 // Initialize int64 locals. | 487 builder_->set_module(module_); |
465 if (function_env_->local_i64_count > 0) { | |
466 TFNode* zero = builder_->Int64Constant(0); | |
467 for (uint32_t i = 0; i < function_env_->local_i64_count; i++) { | |
468 ssa_env->locals[pos++] = zero; | |
469 } | |
470 } | |
471 // Initialize float32 locals. | |
472 if (function_env_->local_f32_count > 0) { | |
473 TFNode* zero = builder_->Float32Constant(0); | |
474 for (uint32_t i = 0; i < function_env_->local_f32_count; i++) { | |
475 ssa_env->locals[pos++] = zero; | |
476 } | |
477 } | |
478 // Initialize float64 locals. | |
479 if (function_env_->local_f64_count > 0) { | |
480 TFNode* zero = builder_->Float64Constant(0); | |
481 for (uint32_t i = 0; i < function_env_->local_f64_count; i++) { | |
482 ssa_env->locals[pos++] = zero; | |
483 } | |
484 } | |
485 DCHECK_EQ(function_env_->total_locals, pos); | |
486 DCHECK_EQ(EnvironmentCount(), pos); | |
487 builder_->set_module(function_env_->module); | |
488 } | 488 } |
489 ssa_env->control = start; | 489 ssa_env->control = start; |
490 ssa_env->effect = start; | 490 ssa_env->effect = start; |
491 SetEnv("initial", ssa_env); | 491 SetEnv("initial", ssa_env); |
492 } | 492 } |
493 | 493 |
| 494 TFNode* DefaultValue(LocalType type) { |
| 495 switch (type) { |
| 496 case kAstI32: |
| 497 return builder_->Int32Constant(0); |
| 498 case kAstI64: |
| 499 return builder_->Int64Constant(0); |
| 500 case kAstF32: |
| 501 return builder_->Float32Constant(0); |
| 502 case kAstF64: |
| 503 return builder_->Float64Constant(0); |
| 504 default: |
| 505 UNREACHABLE(); |
| 506 return nullptr; |
| 507 } |
| 508 } |
| 509 |
494 void Leaf(LocalType type, TFNode* node = nullptr) { | 510 void Leaf(LocalType type, TFNode* node = nullptr) { |
495 size_t size = sizeof(Tree); | 511 size_t size = sizeof(Tree); |
496 Tree* tree = reinterpret_cast<Tree*>(zone_->New(size)); | 512 Tree* tree = reinterpret_cast<Tree*>(zone_->New(size)); |
497 tree->type = type; | 513 tree->type = type; |
498 tree->count = 0; | 514 tree->count = 0; |
499 tree->pc = pc_; | 515 tree->pc = pc_; |
500 tree->node = node; | 516 tree->node = node; |
501 tree->children[0] = nullptr; | 517 tree->children[0] = nullptr; |
502 Reduce(tree); | 518 Reduce(tree); |
503 } | 519 } |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
542 static const int kMaxIndent = 64; | 558 static const int kMaxIndent = 64; |
543 static char bytes[kMaxIndent + 1]; | 559 static char bytes[kMaxIndent + 1]; |
544 for (int i = 0; i < kMaxIndent; i++) bytes[i] = ' '; | 560 for (int i = 0; i < kMaxIndent; i++) bytes[i] = ' '; |
545 bytes[kMaxIndent] = 0; | 561 bytes[kMaxIndent] = 0; |
546 if (stack_.size() < kMaxIndent / 2) { | 562 if (stack_.size() < kMaxIndent / 2) { |
547 bytes[stack_.size() * 2] = 0; | 563 bytes[stack_.size() * 2] = 0; |
548 } | 564 } |
549 return bytes; | 565 return bytes; |
550 } | 566 } |
551 | 567 |
| 568 // Decodes the locals declarations, if any, populating {local_type_vec_}. |
| 569 void DecodeLocalDecls() { |
| 570 DCHECK_EQ(0, local_type_vec_.size()); |
| 571 // Initialize {local_type_vec} from signature. |
| 572 if (sig_) { |
| 573 local_type_vec_.reserve(sig_->parameter_count()); |
| 574 for (size_t i = 0; i < sig_->parameter_count(); i++) { |
| 575 local_type_vec_.push_back(sig_->GetParam(i)); |
| 576 } |
| 577 } |
| 578 // Decode local declarations, if any. |
| 579 int length; |
| 580 uint32_t entries = consume_u32v(&length, "local decls count"); |
| 581 while (entries-- > 0 && pc_ < limit_) { |
| 582 uint32_t count = consume_u32v(&length, "local count"); |
| 583 byte code = consume_u8("local type"); |
| 584 LocalType type; |
| 585 switch (code) { |
| 586 case kLocalI32: |
| 587 type = kAstI32; |
| 588 break; |
| 589 case kLocalI64: |
| 590 type = kAstI64; |
| 591 break; |
| 592 case kLocalF32: |
| 593 type = kAstF32; |
| 594 break; |
| 595 case kLocalF64: |
| 596 type = kAstF64; |
| 597 break; |
| 598 default: |
| 599 error(pc_ - 1, "invalid local type"); |
| 600 return; |
| 601 } |
| 602 local_type_vec_.insert(local_type_vec_.end(), count, type); |
| 603 } |
| 604 total_locals_ = local_type_vec_.size(); |
| 605 } |
| 606 |
552 // Decodes the body of a function, producing reduced trees into {result}. | 607 // Decodes the body of a function, producing reduced trees into {result}. |
553 void DecodeFunctionBody() { | 608 void DecodeFunctionBody() { |
554 TRACE("wasm-decode %p...%p (%d bytes) %s\n", | 609 TRACE("wasm-decode %p...%p (%d bytes) %s\n", |
555 reinterpret_cast<const void*>(start_), | 610 reinterpret_cast<const void*>(start_), |
556 reinterpret_cast<const void*>(limit_), | 611 reinterpret_cast<const void*>(limit_), |
557 static_cast<int>(limit_ - start_), builder_ ? "graph building" : ""); | 612 static_cast<int>(limit_ - start_), builder_ ? "graph building" : ""); |
558 | 613 |
559 if (pc_ >= limit_) return; // Nothing to do. | 614 if (pc_ >= limit_) return; // Nothing to do. |
560 | 615 |
561 while (true) { // decoding loop. | 616 while (true) { // decoding loop. |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
645 } | 700 } |
646 case kExprBrTable: { | 701 case kExprBrTable: { |
647 BranchTableOperand operand(this, pc_); | 702 BranchTableOperand operand(this, pc_); |
648 if (Validate(pc_, operand, blocks_.size())) { | 703 if (Validate(pc_, operand, blocks_.size())) { |
649 Shift(kAstEnd, 1); | 704 Shift(kAstEnd, 1); |
650 } | 705 } |
651 len = 1 + operand.length; | 706 len = 1 + operand.length; |
652 break; | 707 break; |
653 } | 708 } |
654 case kExprReturn: { | 709 case kExprReturn: { |
655 int count = static_cast<int>(function_env_->sig->return_count()); | 710 int count = static_cast<int>(sig_->return_count()); |
656 if (count == 0) { | 711 if (count == 0) { |
657 BUILD(Return, 0, builder_->Buffer(0)); | 712 BUILD(Return, 0, builder_->Buffer(0)); |
658 ssa_env_->Kill(); | 713 ssa_env_->Kill(); |
659 Leaf(kAstEnd); | 714 Leaf(kAstEnd); |
660 } else { | 715 } else { |
661 Shift(kAstEnd, count); | 716 Shift(kAstEnd, count); |
662 } | 717 } |
663 break; | 718 break; |
664 } | 719 } |
665 case kExprUnreachable: { | 720 case kExprUnreachable: { |
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
802 ImportIndexOperand operand(this, pc_); | 857 ImportIndexOperand operand(this, pc_); |
803 if (Validate(pc_, operand)) { | 858 if (Validate(pc_, operand)) { |
804 LocalType type = operand.sig->return_count() == 0 | 859 LocalType type = operand.sig->return_count() == 0 |
805 ? kAstStmt | 860 ? kAstStmt |
806 : operand.sig->GetReturn(); | 861 : operand.sig->GetReturn(); |
807 Shift(type, static_cast<int>(operand.sig->parameter_count())); | 862 Shift(type, static_cast<int>(operand.sig->parameter_count())); |
808 } | 863 } |
809 len = 1 + operand.length; | 864 len = 1 + operand.length; |
810 break; | 865 break; |
811 } | 866 } |
| 867 case kExprDeclLocals: |
812 default: | 868 default: |
813 error("Invalid opcode"); | 869 error("Invalid opcode"); |
814 return; | 870 return; |
815 } | 871 } |
816 pc_ += len; | 872 pc_ += len; |
817 if (pc_ >= limit_) { | 873 if (pc_ >= limit_) { |
818 // End of code reached or exceeded. | 874 // End of code reached or exceeded. |
819 if (pc_ > limit_ && ok()) { | 875 if (pc_ > limit_ && ok()) { |
820 error("Beyond end of code"); | 876 error("Beyond end of code"); |
821 } | 877 } |
(...skipping 12 matching lines...) Expand all Loading... |
834 return 1 + operand.length; | 890 return 1 + operand.length; |
835 } | 891 } |
836 | 892 |
837 int DecodeStoreMem(const byte* pc, LocalType type) { | 893 int DecodeStoreMem(const byte* pc, LocalType type) { |
838 MemoryAccessOperand operand(this, pc); | 894 MemoryAccessOperand operand(this, pc); |
839 Shift(type, 2); | 895 Shift(type, 2); |
840 return 1 + operand.length; | 896 return 1 + operand.length; |
841 } | 897 } |
842 | 898 |
843 void AddImplicitReturnAtEnd() { | 899 void AddImplicitReturnAtEnd() { |
844 int retcount = static_cast<int>(function_env_->sig->return_count()); | 900 int retcount = static_cast<int>(sig_->return_count()); |
845 if (retcount == 0) { | 901 if (retcount == 0) { |
846 BUILD0(ReturnVoid); | 902 BUILD0(ReturnVoid); |
847 return; | 903 return; |
848 } | 904 } |
849 | 905 |
850 if (static_cast<int>(trees_.size()) < retcount) { | 906 if (static_cast<int>(trees_.size()) < retcount) { |
851 error(limit_, nullptr, | 907 error(limit_, nullptr, |
852 "ImplicitReturn expects %d arguments, only %d remain", retcount, | 908 "ImplicitReturn expects %d arguments, only %d remain", retcount, |
853 static_cast<int>(trees_.size())); | 909 static_cast<int>(trees_.size())); |
854 return; | 910 return; |
855 } | 911 } |
856 | 912 |
857 TRACE("wasm-decode implicit return of %d args\n", retcount); | 913 TRACE("wasm-decode implicit return of %d args\n", retcount); |
858 | 914 |
859 TFNode** buffer = BUILD(Buffer, retcount); | 915 TFNode** buffer = BUILD(Buffer, retcount); |
860 for (int index = 0; index < retcount; index++) { | 916 for (int index = 0; index < retcount; index++) { |
861 Tree* tree = trees_[trees_.size() - 1 - index]; | 917 Tree* tree = trees_[trees_.size() - 1 - index]; |
862 if (buffer) buffer[index] = tree->node; | 918 if (buffer) buffer[index] = tree->node; |
863 LocalType expected = function_env_->sig->GetReturn(index); | 919 LocalType expected = sig_->GetReturn(index); |
864 if (tree->type != expected) { | 920 if (tree->type != expected) { |
865 error(limit_, tree->pc, | 921 error(limit_, tree->pc, |
866 "ImplicitReturn[%d] expected type %s, found %s of type %s", index, | 922 "ImplicitReturn[%d] expected type %s, found %s of type %s", index, |
867 WasmOpcodes::TypeName(expected), | 923 WasmOpcodes::TypeName(expected), |
868 WasmOpcodes::OpcodeName(tree->opcode()), | 924 WasmOpcodes::OpcodeName(tree->opcode()), |
869 WasmOpcodes::TypeName(tree->type)); | 925 WasmOpcodes::TypeName(tree->type)); |
870 return; | 926 return; |
871 } | 927 } |
872 } | 928 } |
873 | 929 |
(...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1059 : BUILD(IfValue, i, sw); | 1115 : BUILD(IfValue, i, sw); |
1060 } | 1116 } |
1061 SsaEnv* tenv = blocks_[blocks_.size() - target - 1].ssa_env; | 1117 SsaEnv* tenv = blocks_[blocks_.size() - target - 1].ssa_env; |
1062 Goto(env, tenv); | 1118 Goto(env, tenv); |
1063 } | 1119 } |
1064 ssa_env_ = prev; | 1120 ssa_env_ = prev; |
1065 } | 1121 } |
1066 break; | 1122 break; |
1067 } | 1123 } |
1068 case kExprReturn: { | 1124 case kExprReturn: { |
1069 TypeCheckLast(p, function_env_->sig->GetReturn(p->index - 1)); | 1125 TypeCheckLast(p, sig_->GetReturn(p->index - 1)); |
1070 if (p->done()) { | 1126 if (p->done()) { |
1071 if (build()) { | 1127 if (build()) { |
1072 int count = p->tree->count; | 1128 int count = p->tree->count; |
1073 TFNode** buffer = builder_->Buffer(count); | 1129 TFNode** buffer = builder_->Buffer(count); |
1074 for (int i = 0; i < count; i++) { | 1130 for (int i = 0; i < count; i++) { |
1075 buffer[i] = p->tree->children[i]->node; | 1131 buffer[i] = p->tree->children[i]->node; |
1076 } | 1132 } |
1077 BUILD(Return, count, buffer); | 1133 BUILD(Return, count, buffer); |
1078 } | 1134 } |
1079 ssa_env_->Kill(SsaEnv::kControlEnd); | 1135 ssa_env_->Kill(SsaEnv::kControlEnd); |
(...skipping 259 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1339 if (from->effect != to->effect) { | 1395 if (from->effect != to->effect) { |
1340 TFNode* effects[] = {to->effect, from->effect, merge}; | 1396 TFNode* effects[] = {to->effect, from->effect, merge}; |
1341 to->effect = builder_->EffectPhi(2, effects, merge); | 1397 to->effect = builder_->EffectPhi(2, effects, merge); |
1342 } | 1398 } |
1343 // Merge SSA values. | 1399 // Merge SSA values. |
1344 for (int i = EnvironmentCount() - 1; i >= 0; i--) { | 1400 for (int i = EnvironmentCount() - 1; i >= 0; i--) { |
1345 TFNode* a = to->locals[i]; | 1401 TFNode* a = to->locals[i]; |
1346 TFNode* b = from->locals[i]; | 1402 TFNode* b = from->locals[i]; |
1347 if (a != b) { | 1403 if (a != b) { |
1348 TFNode* vals[] = {a, b}; | 1404 TFNode* vals[] = {a, b}; |
1349 to->locals[i] = | 1405 to->locals[i] = builder_->Phi(local_type_vec_[i], 2, vals, merge); |
1350 builder_->Phi(function_env_->GetLocalType(i), 2, vals, merge); | |
1351 } | 1406 } |
1352 } | 1407 } |
1353 break; | 1408 break; |
1354 } | 1409 } |
1355 case SsaEnv::kMerged: { | 1410 case SsaEnv::kMerged: { |
1356 if (!builder_) break; | 1411 if (!builder_) break; |
1357 TFNode* merge = to->control; | 1412 TFNode* merge = to->control; |
1358 // Extend the existing merge. | 1413 // Extend the existing merge. |
1359 builder_->AppendToMerge(merge, from->control); | 1414 builder_->AppendToMerge(merge, from->control); |
1360 // Merge effects. | 1415 // Merge effects. |
(...skipping 14 matching lines...) Expand all Loading... |
1375 TFNode* fnode = from->locals[i]; | 1430 TFNode* fnode = from->locals[i]; |
1376 if (builder_->IsPhiWithMerge(tnode, merge)) { | 1431 if (builder_->IsPhiWithMerge(tnode, merge)) { |
1377 builder_->AppendToPhi(merge, tnode, fnode); | 1432 builder_->AppendToPhi(merge, tnode, fnode); |
1378 } else if (tnode != fnode) { | 1433 } else if (tnode != fnode) { |
1379 uint32_t count = builder_->InputCount(merge); | 1434 uint32_t count = builder_->InputCount(merge); |
1380 TFNode** vals = builder_->Buffer(count); | 1435 TFNode** vals = builder_->Buffer(count); |
1381 for (uint32_t j = 0; j < count - 1; j++) { | 1436 for (uint32_t j = 0; j < count - 1; j++) { |
1382 vals[j] = tnode; | 1437 vals[j] = tnode; |
1383 } | 1438 } |
1384 vals[count - 1] = fnode; | 1439 vals[count - 1] = fnode; |
1385 to->locals[i] = builder_->Phi(function_env_->GetLocalType(i), count, | 1440 to->locals[i] = |
1386 vals, merge); | 1441 builder_->Phi(local_type_vec_[i], count, vals, merge); |
1387 } | 1442 } |
1388 } | 1443 } |
1389 break; | 1444 break; |
1390 } | 1445 } |
1391 default: | 1446 default: |
1392 UNREACHABLE(); | 1447 UNREACHABLE(); |
1393 } | 1448 } |
1394 return from->Kill(); | 1449 return from->Kill(); |
1395 } | 1450 } |
1396 | 1451 |
(...skipping 22 matching lines...) Expand all Loading... |
1419 } | 1474 } |
1420 | 1475 |
1421 void PrepareForLoop(SsaEnv* env) { | 1476 void PrepareForLoop(SsaEnv* env) { |
1422 if (env->go()) { | 1477 if (env->go()) { |
1423 env->state = SsaEnv::kMerged; | 1478 env->state = SsaEnv::kMerged; |
1424 if (builder_) { | 1479 if (builder_) { |
1425 env->control = builder_->Loop(env->control); | 1480 env->control = builder_->Loop(env->control); |
1426 env->effect = builder_->EffectPhi(1, &env->effect, env->control); | 1481 env->effect = builder_->EffectPhi(1, &env->effect, env->control); |
1427 builder_->Terminate(env->effect, env->control); | 1482 builder_->Terminate(env->effect, env->control); |
1428 for (int i = EnvironmentCount() - 1; i >= 0; i--) { | 1483 for (int i = EnvironmentCount() - 1; i >= 0; i--) { |
1429 env->locals[i] = builder_->Phi(function_env_->GetLocalType(i), 1, | 1484 env->locals[i] = builder_->Phi(local_type_vec_[i], 1, &env->locals[i], |
1430 &env->locals[i], env->control); | 1485 env->control); |
1431 } | 1486 } |
1432 } | 1487 } |
1433 } | 1488 } |
1434 } | 1489 } |
1435 | 1490 |
1436 // Create a complete copy of the {from}. | 1491 // Create a complete copy of the {from}. |
1437 SsaEnv* Split(SsaEnv* from) { | 1492 SsaEnv* Split(SsaEnv* from) { |
1438 DCHECK_NOT_NULL(from); | 1493 DCHECK_NOT_NULL(from); |
1439 SsaEnv* result = reinterpret_cast<SsaEnv*>(zone_->New(sizeof(SsaEnv))); | 1494 SsaEnv* result = reinterpret_cast<SsaEnv*>(zone_->New(sizeof(SsaEnv))); |
1440 size_t size = sizeof(TFNode*) * EnvironmentCount(); | 1495 size_t size = sizeof(TFNode*) * EnvironmentCount(); |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1474 SsaEnv* UnreachableEnv() { | 1529 SsaEnv* UnreachableEnv() { |
1475 SsaEnv* result = reinterpret_cast<SsaEnv*>(zone_->New(sizeof(SsaEnv))); | 1530 SsaEnv* result = reinterpret_cast<SsaEnv*>(zone_->New(sizeof(SsaEnv))); |
1476 result->state = SsaEnv::kUnreachable; | 1531 result->state = SsaEnv::kUnreachable; |
1477 result->control = nullptr; | 1532 result->control = nullptr; |
1478 result->effect = nullptr; | 1533 result->effect = nullptr; |
1479 result->locals = nullptr; | 1534 result->locals = nullptr; |
1480 return result; | 1535 return result; |
1481 } | 1536 } |
1482 | 1537 |
1483 int EnvironmentCount() { | 1538 int EnvironmentCount() { |
1484 if (builder_) return static_cast<int>(function_env_->GetLocalCount()); | 1539 if (builder_) return static_cast<int>(local_type_vec_.size()); |
1485 return 0; // if we aren't building a graph, don't bother with SSA renaming. | 1540 return 0; // if we aren't building a graph, don't bother with SSA renaming. |
1486 } | 1541 } |
1487 | 1542 |
1488 virtual void onFirstError() { | 1543 virtual void onFirstError() { |
1489 limit_ = start_; // Terminate decoding loop. | 1544 limit_ = start_; // Terminate decoding loop. |
1490 builder_ = nullptr; // Don't build any more nodes. | 1545 builder_ = nullptr; // Don't build any more nodes. |
1491 #if DEBUG | 1546 #if DEBUG |
1492 PrintStackForDebugging(); | 1547 PrintStackForDebugging(); |
1493 #endif | 1548 #endif |
1494 } | 1549 } |
(...skipping 15 matching lines...) Expand all Loading... |
1510 WasmOpcodes::OpcodeName(child->opcode()), child->count); | 1565 WasmOpcodes::OpcodeName(child->opcode()), child->count); |
1511 if (child->node) { | 1566 if (child->node) { |
1512 PrintF(" => TF"); | 1567 PrintF(" => TF"); |
1513 compiler::WasmGraphBuilder::PrintDebugName(child->node); | 1568 compiler::WasmGraphBuilder::PrintDebugName(child->node); |
1514 } | 1569 } |
1515 PrintF("\n"); | 1570 PrintF("\n"); |
1516 } | 1571 } |
1517 PrintProduction(depth + 1); | 1572 PrintProduction(depth + 1); |
1518 } | 1573 } |
1519 #endif | 1574 #endif |
| 1575 |
| 1576 BitVector* AnalyzeLoopAssignment(const byte* pc) { |
| 1577 if (pc >= limit_) return nullptr; |
| 1578 if (*pc != kExprLoop) return nullptr; |
| 1579 |
| 1580 BitVector* assigned = |
| 1581 new (zone_) BitVector(static_cast<int>(total_locals_), zone_); |
| 1582 // Keep a stack to model the nesting of expressions. |
| 1583 std::vector<int> arity_stack; |
| 1584 arity_stack.push_back(OpcodeArity(pc)); |
| 1585 pc += OpcodeLength(pc); |
| 1586 |
| 1587 // Iteratively process all AST nodes nested inside the loop. |
| 1588 while (pc < limit_) { |
| 1589 WasmOpcode opcode = static_cast<WasmOpcode>(*pc); |
| 1590 int arity = 0; |
| 1591 int length = 1; |
| 1592 if (opcode == kExprSetLocal) { |
| 1593 LocalIndexOperand operand(this, pc); |
| 1594 if (assigned->length() > 0 && |
| 1595 static_cast<int>(operand.index) < assigned->length()) { |
| 1596 // Unverified code might have an out-of-bounds index. |
| 1597 assigned->Add(operand.index); |
| 1598 } |
| 1599 arity = 1; |
| 1600 length = 1 + operand.length; |
| 1601 } else { |
| 1602 arity = OpcodeArity(pc); |
| 1603 length = OpcodeLength(pc); |
| 1604 } |
| 1605 |
| 1606 pc += length; |
| 1607 arity_stack.push_back(arity); |
| 1608 while (arity_stack.back() == 0) { |
| 1609 arity_stack.pop_back(); |
| 1610 if (arity_stack.empty()) return assigned; // reached end of loop |
| 1611 arity_stack.back()--; |
| 1612 } |
| 1613 } |
| 1614 return assigned; |
| 1615 } |
1520 }; | 1616 }; |
1521 | 1617 |
| 1618 std::vector<LocalType>* DecodeLocalDeclsForTesting(const byte* start, |
| 1619 const byte* end) { |
| 1620 Zone zone; |
| 1621 FunctionBody body = {nullptr, nullptr, nullptr, start, end}; |
| 1622 SR_WasmDecoder decoder(&zone, nullptr, body); |
| 1623 return decoder.DecodeLocalDeclsForTesting(); |
| 1624 } |
1522 | 1625 |
1523 TreeResult VerifyWasmCode(FunctionEnv* env, const byte* base, const byte* start, | 1626 TreeResult VerifyWasmCode(FunctionBody& body) { |
1524 const byte* end) { | |
1525 Zone zone; | 1627 Zone zone; |
1526 LR_WasmDecoder decoder(&zone, nullptr); | 1628 SR_WasmDecoder decoder(&zone, nullptr, body); |
1527 TreeResult result = decoder.Decode(env, base, start, end); | 1629 TreeResult result = decoder.Decode(); |
1528 return result; | 1630 return result; |
1529 } | 1631 } |
1530 | 1632 |
1531 | 1633 TreeResult BuildTFGraph(TFBuilder* builder, FunctionBody& body) { |
1532 TreeResult BuildTFGraph(TFBuilder* builder, FunctionEnv* env, const byte* base, | |
1533 const byte* start, const byte* end) { | |
1534 Zone zone; | 1634 Zone zone; |
1535 LR_WasmDecoder decoder(&zone, builder); | 1635 SR_WasmDecoder decoder(&zone, builder, body); |
1536 TreeResult result = decoder.Decode(env, base, start, end); | 1636 TreeResult result = decoder.Decode(); |
1537 return result; | 1637 return result; |
1538 } | 1638 } |
1539 | 1639 |
1540 | 1640 |
1541 std::ostream& operator<<(std::ostream& os, const Tree& tree) { | 1641 std::ostream& operator<<(std::ostream& os, const Tree& tree) { |
1542 if (tree.pc == nullptr) { | 1642 if (tree.pc == nullptr) { |
1543 os << "null"; | 1643 os << "null"; |
1544 return os; | 1644 return os; |
1545 } | 1645 } |
1546 PrintF("%s", WasmOpcodes::OpcodeName(tree.opcode())); | 1646 PrintF("%s", WasmOpcodes::OpcodeName(tree.opcode())); |
(...skipping 11 matching lines...) Expand all Loading... |
1558 const byte* limit, | 1658 const byte* limit, |
1559 int* length, | 1659 int* length, |
1560 uint32_t* result) { | 1660 uint32_t* result) { |
1561 Decoder decoder(pc, limit); | 1661 Decoder decoder(pc, limit); |
1562 *result = decoder.checked_read_u32v(pc, 0, length); | 1662 *result = decoder.checked_read_u32v(pc, 0, length); |
1563 if (decoder.ok()) return kNoError; | 1663 if (decoder.ok()) return kNoError; |
1564 return (limit - pc) > 1 ? kInvalidLEB128 : kMissingLEB128; | 1664 return (limit - pc) > 1 ? kInvalidLEB128 : kMissingLEB128; |
1565 } | 1665 } |
1566 | 1666 |
1567 int OpcodeLength(const byte* pc, const byte* end) { | 1667 int OpcodeLength(const byte* pc, const byte* end) { |
1568 WasmDecoder decoder(nullptr, pc, end); | 1668 WasmDecoder decoder(nullptr, nullptr, pc, end); |
1569 return decoder.OpcodeLength(pc); | 1669 return decoder.OpcodeLength(pc); |
1570 } | 1670 } |
1571 | 1671 |
1572 int OpcodeArity(FunctionEnv* env, const byte* pc, const byte* end) { | 1672 int OpcodeArity(ModuleEnv* module, FunctionSig* sig, const byte* pc, |
1573 WasmDecoder decoder(env, pc, end); | 1673 const byte* end) { |
| 1674 WasmDecoder decoder(module, sig, pc, end); |
1574 return decoder.OpcodeArity(pc); | 1675 return decoder.OpcodeArity(pc); |
1575 } | 1676 } |
1576 | 1677 |
1577 void PrintAst(FunctionEnv* env, const byte* start, const byte* end) { | 1678 void PrintAst(FunctionBody& body) { |
1578 WasmDecoder decoder(env, start, end); | 1679 WasmDecoder decoder(body.module, body.sig, body.start, body.end); |
1579 const byte* pc = start; | 1680 const byte* pc = body.start; |
1580 std::vector<int> arity_stack; | 1681 std::vector<int> arity_stack; |
1581 while (pc < end) { | 1682 while (pc < body.end) { |
1582 int arity = decoder.OpcodeArity(pc); | 1683 int arity = decoder.OpcodeArity(pc); |
1583 size_t length = decoder.OpcodeLength(pc); | 1684 size_t length = decoder.OpcodeLength(pc); |
1584 | 1685 |
1585 for (auto arity : arity_stack) { | 1686 for (auto arity : arity_stack) { |
1586 printf(" "); | 1687 printf(" "); |
1587 USE(arity); | 1688 USE(arity); |
1588 } | 1689 } |
1589 | 1690 |
1590 WasmOpcode opcode = static_cast<WasmOpcode>(*pc); | 1691 WasmOpcode opcode = static_cast<WasmOpcode>(*pc); |
1591 printf("k%s,", WasmOpcodes::OpcodeName(opcode)); | 1692 printf("k%s,", WasmOpcodes::OpcodeName(opcode)); |
1592 | 1693 |
1593 for (size_t i = 1; i < length; i++) { | 1694 for (size_t i = 1; i < length; i++) { |
1594 printf(" 0x%02x,", pc[i]); | 1695 printf(" 0x%02x,", pc[i]); |
1595 } | 1696 } |
1596 pc += length; | 1697 pc += length; |
1597 printf("\n"); | 1698 printf("\n"); |
1598 | 1699 |
1599 arity_stack.push_back(arity); | 1700 arity_stack.push_back(arity); |
1600 while (arity_stack.back() == 0) { | 1701 while (arity_stack.back() == 0) { |
1601 arity_stack.pop_back(); | 1702 arity_stack.pop_back(); |
1602 if (arity_stack.empty()) break; | 1703 if (arity_stack.empty()) break; |
1603 arity_stack.back()--; | 1704 arity_stack.back()--; |
1604 } | 1705 } |
1605 } | 1706 } |
1606 } | 1707 } |
1607 | 1708 |
1608 // Analyzes loop bodies for static assignments to locals, which helps in | 1709 BitVector* AnalyzeLoopAssignmentForTesting(Zone* zone, size_t num_locals, |
1609 // reducing the number of phis introduced at loop headers. | |
1610 class LoopAssignmentAnalyzer : public WasmDecoder { | |
1611 public: | |
1612 LoopAssignmentAnalyzer(Zone* zone, FunctionEnv* function_env) : zone_(zone) { | |
1613 function_env_ = function_env; | |
1614 } | |
1615 | |
1616 BitVector* Analyze(const byte* pc, const byte* limit) { | |
1617 Decoder::Reset(pc, limit); | |
1618 if (pc_ >= limit_) return nullptr; | |
1619 if (*pc_ != kExprLoop) return nullptr; | |
1620 | |
1621 BitVector* assigned = | |
1622 new (zone_) BitVector(function_env_->total_locals, zone_); | |
1623 // Keep a stack to model the nesting of expressions. | |
1624 std::vector<int> arity_stack; | |
1625 arity_stack.push_back(OpcodeArity(pc_)); | |
1626 pc_ += OpcodeLength(pc_); | |
1627 | |
1628 // Iteratively process all AST nodes nested inside the loop. | |
1629 while (pc_ < limit_) { | |
1630 WasmOpcode opcode = static_cast<WasmOpcode>(*pc_); | |
1631 int arity = 0; | |
1632 int length = 1; | |
1633 if (opcode == kExprSetLocal) { | |
1634 LocalIndexOperand operand(this, pc_); | |
1635 if (assigned->length() > 0 && | |
1636 static_cast<int>(operand.index) < assigned->length()) { | |
1637 // Unverified code might have an out-of-bounds index. | |
1638 assigned->Add(operand.index); | |
1639 } | |
1640 arity = 1; | |
1641 length = 1 + operand.length; | |
1642 } else { | |
1643 arity = OpcodeArity(pc_); | |
1644 length = OpcodeLength(pc_); | |
1645 } | |
1646 | |
1647 pc_ += length; | |
1648 arity_stack.push_back(arity); | |
1649 while (arity_stack.back() == 0) { | |
1650 arity_stack.pop_back(); | |
1651 if (arity_stack.empty()) return assigned; // reached end of loop | |
1652 arity_stack.back()--; | |
1653 } | |
1654 } | |
1655 return assigned; | |
1656 } | |
1657 | |
1658 private: | |
1659 Zone* zone_; | |
1660 }; | |
1661 | |
1662 | |
1663 BitVector* AnalyzeLoopAssignmentForTesting(Zone* zone, FunctionEnv* env, | |
1664 const byte* start, const byte* end) { | 1710 const byte* start, const byte* end) { |
1665 LoopAssignmentAnalyzer analyzer(zone, env); | 1711 FunctionBody body = {nullptr, nullptr, nullptr, start, end}; |
1666 return analyzer.Analyze(start, end); | 1712 SR_WasmDecoder decoder(zone, nullptr, body); |
| 1713 return decoder.AnalyzeLoopAssignmentForTesting(start, num_locals); |
1667 } | 1714 } |
1668 | 1715 |
1669 } // namespace wasm | 1716 } // namespace wasm |
1670 } // namespace internal | 1717 } // namespace internal |
1671 } // namespace v8 | 1718 } // namespace v8 |
OLD | NEW |