Chromium Code Reviews| 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 |