| 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 |