| 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/signature.h" | 5 #include "src/signature.h" | 
| 6 | 6 | 
| 7 #include "src/bit-vector.h" | 7 #include "src/bit-vector.h" | 
| 8 #include "src/flags.h" | 8 #include "src/flags.h" | 
| 9 #include "src/handles.h" | 9 #include "src/handles.h" | 
| 10 #include "src/zone-containers.h" | 10 #include "src/zone-containers.h" | 
| (...skipping 24 matching lines...) Expand all  Loading... | 
| 35 struct Tree { | 35 struct Tree { | 
| 36   LocalType type;     // tree type. | 36   LocalType type;     // tree type. | 
| 37   uint32_t count;     // number of children. | 37   uint32_t count;     // number of children. | 
| 38   const byte* pc;     // start of the syntax tree. | 38   const byte* pc;     // start of the syntax tree. | 
| 39   TFNode* node;       // node in the TurboFan graph. | 39   TFNode* node;       // node in the TurboFan graph. | 
| 40   Tree* children[1];  // pointers to children. | 40   Tree* children[1];  // pointers to children. | 
| 41 | 41 | 
| 42   WasmOpcode opcode() const { return static_cast<WasmOpcode>(*pc); } | 42   WasmOpcode opcode() const { return static_cast<WasmOpcode>(*pc); } | 
| 43 }; | 43 }; | 
| 44 | 44 | 
| 45 // A production represents an incomplete decoded tree in the LR decoder. |  | 
| 46 struct Production { |  | 
| 47   Tree* tree;  // the root of the syntax tree. |  | 
| 48   int index;   // the current index into the children of the tree. |  | 
| 49 |  | 
| 50   WasmOpcode opcode() const { return static_cast<WasmOpcode>(*pc()); } |  | 
| 51   const byte* pc() const { return tree->pc; } |  | 
| 52   bool done() const { return index >= static_cast<int>(tree->count); } |  | 
| 53   Tree* last() const { return index > 0 ? tree->children[index - 1] : nullptr; } |  | 
| 54 }; |  | 
| 55 |  | 
| 56 // An SsaEnv environment carries the current local variable renaming | 45 // An SsaEnv environment carries the current local variable renaming | 
| 57 // as well as the current effect and control dependency in the TF graph. | 46 // as well as the current effect and control dependency in the TF graph. | 
| 58 // It maintains a control state that tracks whether the environment | 47 // It maintains a control state that tracks whether the environment | 
| 59 // is reachable, has reached a control end, or has been merged. | 48 // is reachable, has reached a control end, or has been merged. | 
| 60 struct SsaEnv { | 49 struct SsaEnv { | 
| 61   enum State { kControlEnd, kUnreachable, kReached, kMerged }; | 50   enum State { kControlEnd, kUnreachable, kReached, kMerged }; | 
| 62 | 51 | 
| 63   State state; | 52   State state; | 
| 64   TFNode* control; | 53   TFNode* control; | 
| 65   TFNode* effect; | 54   TFNode* effect; | 
| 66   TFNode** locals; | 55   TFNode** locals; | 
| 67 | 56 | 
| 68   bool go() { return state >= kReached; } | 57   bool go() { return state >= kReached; } | 
| 69   void Kill(State new_state = kControlEnd) { | 58   void Kill(State new_state = kControlEnd) { | 
| 70     state = new_state; | 59     state = new_state; | 
| 71     locals = nullptr; | 60     locals = nullptr; | 
| 72     control = nullptr; | 61     control = nullptr; | 
| 73     effect = nullptr; | 62     effect = nullptr; | 
| 74   } | 63   } | 
|  | 64   void SetNotMerged() { | 
|  | 65     if (state == kMerged) state = kReached; | 
|  | 66   } | 
| 75 }; | 67 }; | 
| 76 | 68 | 
| 77 // An entry in the stack of blocks during decoding. | 69 // An entry on the value stack. | 
| 78 struct Block { | 70 struct Value { | 
| 79   SsaEnv* ssa_env;  // SSA renaming environment. | 71   const byte* pc; | 
| 80   int stack_depth;  // production stack depth. | 72   TFNode* node; | 
|  | 73   LocalType type; | 
| 81 }; | 74 }; | 
| 82 | 75 | 
| 83 // An entry in the stack of ifs during decoding. | 76 // An entry on the control stack (i.e. if, block, loop). | 
| 84 struct IfEnv { | 77 struct Control { | 
| 85   SsaEnv* false_env; | 78   const byte* pc; | 
| 86   SsaEnv* merge_env; | 79   int stack_depth;    // stack height at the beginning of the construct. | 
| 87   SsaEnv** case_envs; | 80   SsaEnv* end_env;    // end environment for the construct. | 
|  | 81   SsaEnv* false_env;  // false environment (only for if). | 
|  | 82   TFNode* node;       // result node for the construct. | 
|  | 83   LocalType type;     // result type for the construct. | 
|  | 84   bool is_loop;       // true if this is the inner label of a loop. | 
|  | 85 | 
|  | 86   bool is_if() { return *pc == kExprIf; } | 
|  | 87   bool is_block() { return *pc == kExprBlock; } | 
| 88 }; | 88 }; | 
| 89 | 89 | 
| 90 // Macros that build nodes only if there is a graph and the current SSA | 90 // Macros that build nodes only if there is a graph and the current SSA | 
| 91 // environment is reachable from start. This avoids problems with malformed | 91 // environment is reachable from start. This avoids problems with malformed | 
| 92 // TF graphs when decoding inputs that have unreachable code. | 92 // TF graphs when decoding inputs that have unreachable code. | 
| 93 #define BUILD(func, ...) (build() ? builder_->func(__VA_ARGS__) : nullptr) | 93 #define BUILD(func, ...) (build() ? builder_->func(__VA_ARGS__) : nullptr) | 
| 94 #define BUILD0(func) (build() ? builder_->func() : nullptr) | 94 #define BUILD0(func) (build() ? builder_->func() : nullptr) | 
| 95 | 95 | 
| 96 // Generic Wasm bytecode decoder with utilities for decoding operands, | 96 // Generic Wasm bytecode decoder with utilities for decoding operands, | 
| 97 // lengths, etc. | 97 // lengths, etc. | 
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 150     ModuleEnv* m = module_; | 150     ModuleEnv* m = module_; | 
| 151     if (m && m->module && operand.index < m->module->globals.size()) { | 151     if (m && m->module && operand.index < m->module->globals.size()) { | 
| 152       operand.machine_type = m->module->globals[operand.index].type; | 152       operand.machine_type = m->module->globals[operand.index].type; | 
| 153       operand.type = WasmOpcodes::LocalTypeFor(operand.machine_type); | 153       operand.type = WasmOpcodes::LocalTypeFor(operand.machine_type); | 
| 154       return true; | 154       return true; | 
| 155     } | 155     } | 
| 156     error(pc, pc + 1, "invalid global index"); | 156     error(pc, pc + 1, "invalid global index"); | 
| 157     return false; | 157     return false; | 
| 158   } | 158   } | 
| 159 | 159 | 
| 160   inline bool Validate(const byte* pc, FunctionIndexOperand& operand) { | 160   inline bool Validate(const byte* pc, CallFunctionOperand& operand) { | 
| 161     ModuleEnv* m = module_; | 161     ModuleEnv* m = module_; | 
| 162     if (m && m->module && operand.index < m->module->functions.size()) { | 162     if (m && m->module && operand.index < m->module->functions.size()) { | 
| 163       operand.sig = m->module->functions[operand.index].sig; | 163       operand.sig = m->module->functions[operand.index].sig; | 
|  | 164       uint32_t expected = static_cast<uint32_t>(operand.sig->parameter_count()); | 
|  | 165       if (operand.arity != expected) { | 
|  | 166         error(pc, pc + 1, | 
|  | 167               "arity mismatch in direct function call (expected %u, got %u)", | 
|  | 168               expected, operand.arity); | 
|  | 169         return false; | 
|  | 170       } | 
| 164       return true; | 171       return true; | 
| 165     } | 172     } | 
| 166     error(pc, pc + 1, "invalid function index"); | 173     error(pc, pc + 1, "invalid function index"); | 
| 167     return false; | 174     return false; | 
| 168   } | 175   } | 
| 169 | 176 | 
| 170   inline bool Validate(const byte* pc, SignatureIndexOperand& operand) { | 177   inline bool Validate(const byte* pc, CallIndirectOperand& operand) { | 
| 171     ModuleEnv* m = module_; | 178     ModuleEnv* m = module_; | 
| 172     if (m && m->module && operand.index < m->module->signatures.size()) { | 179     if (m && m->module && operand.index < m->module->signatures.size()) { | 
| 173       operand.sig = m->module->signatures[operand.index]; | 180       operand.sig = m->module->signatures[operand.index]; | 
|  | 181       uint32_t expected = static_cast<uint32_t>(operand.sig->parameter_count()); | 
|  | 182       if (operand.arity != expected) { | 
|  | 183         error(pc, pc + 1, | 
|  | 184               "arity mismatch in indirect function call (expected %u, got %u)", | 
|  | 185               expected, operand.arity); | 
|  | 186         return false; | 
|  | 187       } | 
| 174       return true; | 188       return true; | 
| 175     } | 189     } | 
| 176     error(pc, pc + 1, "invalid signature index"); | 190     error(pc, pc + 1, "invalid signature index"); | 
| 177     return false; | 191     return false; | 
| 178   } | 192   } | 
| 179 | 193 | 
| 180   inline bool Validate(const byte* pc, ImportIndexOperand& operand) { | 194   inline bool Validate(const byte* pc, CallImportOperand& operand) { | 
| 181     ModuleEnv* m = module_; | 195     ModuleEnv* m = module_; | 
| 182     if (m && m->module && operand.index < m->module->import_table.size()) { | 196     if (m && m->module && operand.index < m->module->import_table.size()) { | 
| 183       operand.sig = m->module->import_table[operand.index].sig; | 197       operand.sig = m->module->import_table[operand.index].sig; | 
|  | 198       uint32_t expected = static_cast<uint32_t>(operand.sig->parameter_count()); | 
|  | 199       if (operand.arity != expected) { | 
|  | 200         error(pc, pc + 1, "arity mismatch in import call (expected %u, got %u)", | 
|  | 201               expected, operand.arity); | 
|  | 202         return false; | 
|  | 203       } | 
| 184       return true; | 204       return true; | 
| 185     } | 205     } | 
| 186     error(pc, pc + 1, "invalid signature index"); | 206     error(pc, pc + 1, "invalid signature index"); | 
| 187     return false; | 207     return false; | 
| 188   } | 208   } | 
| 189 | 209 | 
| 190   inline bool Validate(const byte* pc, BreakDepthOperand& operand, | 210   inline bool Validate(const byte* pc, BreakDepthOperand& operand, | 
| 191                        ZoneVector<Block>& blocks) { | 211                        ZoneVector<Control>& control) { | 
| 192     if (operand.depth < blocks.size()) { | 212     if (operand.arity > 1) { | 
| 193       operand.target = &blocks[blocks.size() - operand.depth - 1]; | 213       error(pc, pc + 1, "invalid arity for br or br_if"); | 
|  | 214       return false; | 
|  | 215     } | 
|  | 216     if (operand.depth < control.size()) { | 
|  | 217       operand.target = &control[control.size() - operand.depth - 1]; | 
| 194       return true; | 218       return true; | 
| 195     } | 219     } | 
| 196     error(pc, pc + 1, "invalid break depth"); | 220     error(pc, pc + 1, "invalid break depth"); | 
| 197     return false; | 221     return false; | 
| 198   } | 222   } | 
| 199 | 223 | 
| 200   bool Validate(const byte* pc, BranchTableOperand& operand, | 224   bool Validate(const byte* pc, BranchTableOperand& operand, | 
| 201                 size_t block_depth) { | 225                 size_t block_depth) { | 
|  | 226     if (operand.arity > 1) { | 
|  | 227       error(pc, pc + 1, "invalid arity for break"); | 
|  | 228       return false; | 
|  | 229     } | 
| 202     // Verify table. | 230     // Verify table. | 
| 203     for (uint32_t i = 0; i < operand.table_count + 1; i++) { | 231     for (uint32_t i = 0; i < operand.table_count + 1; i++) { | 
| 204       uint32_t target = operand.read_entry(this, i); | 232       uint32_t target = operand.read_entry(this, i); | 
| 205       if (target >= block_depth) { | 233       if (target >= block_depth) { | 
| 206         error(operand.table + i * 2, "improper branch in br_table"); | 234         error(operand.table + i * 2, "improper branch in br_table"); | 
| 207         return false; | 235         return false; | 
| 208       } | 236       } | 
| 209     } | 237     } | 
| 210     return true; | 238     return true; | 
| 211   } | 239   } | 
| (...skipping 10 matching lines...) Expand all  Loading... | 
| 222     switch (static_cast<WasmOpcode>(*pc)) { | 250     switch (static_cast<WasmOpcode>(*pc)) { | 
| 223       case kExprI8Const: | 251       case kExprI8Const: | 
| 224       case kExprI32Const: | 252       case kExprI32Const: | 
| 225       case kExprI64Const: | 253       case kExprI64Const: | 
| 226       case kExprF64Const: | 254       case kExprF64Const: | 
| 227       case kExprF32Const: | 255       case kExprF32Const: | 
| 228       case kExprGetLocal: | 256       case kExprGetLocal: | 
| 229       case kExprLoadGlobal: | 257       case kExprLoadGlobal: | 
| 230       case kExprNop: | 258       case kExprNop: | 
| 231       case kExprUnreachable: | 259       case kExprUnreachable: | 
|  | 260       case kExprEnd: | 
|  | 261       case kExprBlock: | 
|  | 262       case kExprLoop: | 
| 232         return 0; | 263         return 0; | 
| 233 | 264 | 
| 234       case kExprBr: |  | 
| 235       case kExprStoreGlobal: | 265       case kExprStoreGlobal: | 
| 236       case kExprSetLocal: | 266       case kExprSetLocal: | 
|  | 267       case kExprElse: | 
| 237         return 1; | 268         return 1; | 
| 238 | 269 | 
|  | 270       case kExprBr: { | 
|  | 271         BreakDepthOperand operand(this, pc); | 
|  | 272         return operand.arity; | 
|  | 273       } | 
|  | 274       case kExprBrIf: { | 
|  | 275         BreakDepthOperand operand(this, pc); | 
|  | 276         return 1 + operand.arity; | 
|  | 277       } | 
|  | 278       case kExprBrTable: { | 
|  | 279         BranchTableOperand operand(this, pc); | 
|  | 280         return 1 + operand.arity; | 
|  | 281       } | 
|  | 282 | 
| 239       case kExprIf: | 283       case kExprIf: | 
| 240       case kExprBrIf: | 284         return 1; | 
| 241         return 2; |  | 
| 242       case kExprIfElse: |  | 
| 243       case kExprSelect: | 285       case kExprSelect: | 
| 244         return 3; | 286         return 3; | 
| 245 | 287 | 
| 246       case kExprBlock: |  | 
| 247       case kExprLoop: { |  | 
| 248         BlockCountOperand operand(this, pc); |  | 
| 249         return operand.count; |  | 
| 250       } |  | 
| 251 |  | 
| 252       case kExprCallFunction: { | 288       case kExprCallFunction: { | 
| 253         FunctionIndexOperand operand(this, pc); | 289         CallFunctionOperand operand(this, pc); | 
| 254         return static_cast<int>( | 290         return static_cast<int>( | 
| 255             module_->GetFunctionSignature(operand.index)->parameter_count()); | 291             module_->GetFunctionSignature(operand.index)->parameter_count()); | 
| 256       } | 292       } | 
| 257       case kExprCallIndirect: { | 293       case kExprCallIndirect: { | 
| 258         SignatureIndexOperand operand(this, pc); | 294         CallIndirectOperand operand(this, pc); | 
| 259         return 1 + static_cast<int>( | 295         return 1 + static_cast<int>( | 
| 260                        module_->GetSignature(operand.index)->parameter_count()); | 296                        module_->GetSignature(operand.index)->parameter_count()); | 
| 261       } | 297       } | 
| 262       case kExprCallImport: { | 298       case kExprCallImport: { | 
| 263         ImportIndexOperand operand(this, pc); | 299         CallImportOperand operand(this, pc); | 
| 264         return static_cast<int>( | 300         return static_cast<int>( | 
| 265             module_->GetImportSignature(operand.index)->parameter_count()); | 301             module_->GetImportSignature(operand.index)->parameter_count()); | 
| 266       } | 302       } | 
| 267       case kExprReturn: { | 303       case kExprReturn: { | 
| 268         return static_cast<int>(sig_->return_count()); | 304         return static_cast<int>(sig_->return_count()); | 
| 269       } | 305       } | 
| 270       case kExprBrTable: { |  | 
| 271         return 1; |  | 
| 272       } |  | 
| 273 | 306 | 
| 274 #define DECLARE_OPCODE_CASE(name, opcode, sig) \ | 307 #define DECLARE_OPCODE_CASE(name, opcode, sig) \ | 
| 275   case kExpr##name:                            \ | 308   case kExpr##name:                            \ | 
| 276     return kArity_##sig; | 309     return kArity_##sig; | 
| 277 | 310 | 
| 278         FOREACH_LOAD_MEM_OPCODE(DECLARE_OPCODE_CASE) | 311         FOREACH_LOAD_MEM_OPCODE(DECLARE_OPCODE_CASE) | 
| 279         FOREACH_STORE_MEM_OPCODE(DECLARE_OPCODE_CASE) | 312         FOREACH_STORE_MEM_OPCODE(DECLARE_OPCODE_CASE) | 
| 280         FOREACH_MISC_MEM_OPCODE(DECLARE_OPCODE_CASE) | 313         FOREACH_MISC_MEM_OPCODE(DECLARE_OPCODE_CASE) | 
| 281         FOREACH_SIMPLE_OPCODE(DECLARE_OPCODE_CASE) | 314         FOREACH_SIMPLE_OPCODE(DECLARE_OPCODE_CASE) | 
| 282         FOREACH_ASMJS_COMPAT_OPCODE(DECLARE_OPCODE_CASE) | 315         FOREACH_ASMJS_COMPAT_OPCODE(DECLARE_OPCODE_CASE) | 
| 283 #undef DECLARE_OPCODE_CASE | 316 #undef DECLARE_OPCODE_CASE | 
| 284       case kExprDeclLocals: |  | 
| 285       default: | 317       default: | 
| 286         UNREACHABLE(); | 318         UNREACHABLE(); | 
| 287         return 0; | 319         return 0; | 
| 288     } | 320     } | 
| 289   } | 321   } | 
| 290 | 322 | 
| 291   int OpcodeLength(const byte* pc) { | 323   int OpcodeLength(const byte* pc) { | 
| 292     switch (static_cast<WasmOpcode>(*pc)) { | 324     switch (static_cast<WasmOpcode>(*pc)) { | 
| 293 #define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name: | 325 #define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name: | 
| 294       FOREACH_LOAD_MEM_OPCODE(DECLARE_OPCODE_CASE) | 326       FOREACH_LOAD_MEM_OPCODE(DECLARE_OPCODE_CASE) | 
| 295       FOREACH_STORE_MEM_OPCODE(DECLARE_OPCODE_CASE) | 327       FOREACH_STORE_MEM_OPCODE(DECLARE_OPCODE_CASE) | 
| 296 #undef DECLARE_OPCODE_CASE | 328 #undef DECLARE_OPCODE_CASE | 
| 297       { | 329       { | 
| 298         MemoryAccessOperand operand(this, pc); | 330         MemoryAccessOperand operand(this, pc); | 
| 299         return 1 + operand.length; | 331         return 1 + operand.length; | 
| 300       } | 332       } | 
| 301       case kExprBlock: |  | 
| 302       case kExprLoop: { |  | 
| 303         BlockCountOperand operand(this, pc); |  | 
| 304         return 1 + operand.length; |  | 
| 305       } |  | 
| 306       case kExprBr: | 333       case kExprBr: | 
| 307       case kExprBrIf: { | 334       case kExprBrIf: { | 
| 308         BreakDepthOperand operand(this, pc); | 335         BreakDepthOperand operand(this, pc); | 
| 309         return 1 + operand.length; | 336         return 1 + operand.length; | 
| 310       } | 337       } | 
| 311       case kExprStoreGlobal: | 338       case kExprStoreGlobal: | 
| 312       case kExprLoadGlobal: { | 339       case kExprLoadGlobal: { | 
| 313         GlobalIndexOperand operand(this, pc); | 340         GlobalIndexOperand operand(this, pc); | 
| 314         return 1 + operand.length; | 341         return 1 + operand.length; | 
| 315       } | 342       } | 
| 316 | 343 | 
| 317       case kExprCallFunction: { | 344       case kExprCallFunction: { | 
| 318         FunctionIndexOperand operand(this, pc); | 345         CallFunctionOperand operand(this, pc); | 
| 319         return 1 + operand.length; | 346         return 1 + operand.length; | 
| 320       } | 347       } | 
| 321       case kExprCallIndirect: { | 348       case kExprCallIndirect: { | 
| 322         SignatureIndexOperand operand(this, pc); | 349         CallIndirectOperand operand(this, pc); | 
| 323         return 1 + operand.length; | 350         return 1 + operand.length; | 
| 324       } | 351       } | 
| 325       case kExprCallImport: { | 352       case kExprCallImport: { | 
| 326         ImportIndexOperand operand(this, pc); | 353         CallImportOperand operand(this, pc); | 
| 327         return 1 + operand.length; | 354         return 1 + operand.length; | 
| 328       } | 355       } | 
| 329 | 356 | 
| 330       case kExprSetLocal: | 357       case kExprSetLocal: | 
| 331       case kExprGetLocal: { | 358       case kExprGetLocal: { | 
| 332         LocalIndexOperand operand(this, pc); | 359         LocalIndexOperand operand(this, pc); | 
| 333         return 1 + operand.length; | 360         return 1 + operand.length; | 
| 334       } | 361       } | 
| 335       case kExprBrTable: { | 362       case kExprBrTable: { | 
| 336         BranchTableOperand operand(this, pc); | 363         BranchTableOperand operand(this, pc); | 
| 337         return 1 + operand.length; | 364         return 1 + operand.length; | 
| 338       } | 365       } | 
| 339       case kExprI32Const: { | 366       case kExprI32Const: { | 
| 340         ImmI32Operand operand(this, pc); | 367         ImmI32Operand operand(this, pc); | 
| 341         return 1 + operand.length; | 368         return 1 + operand.length; | 
| 342       } | 369       } | 
| 343       case kExprI64Const: { | 370       case kExprI64Const: { | 
| 344         ImmI64Operand operand(this, pc); | 371         ImmI64Operand operand(this, pc); | 
| 345         return 1 + operand.length; | 372         return 1 + operand.length; | 
| 346       } | 373       } | 
| 347       case kExprI8Const: | 374       case kExprI8Const: | 
| 348         return 2; | 375         return 2; | 
| 349       case kExprF32Const: | 376       case kExprF32Const: | 
| 350         return 5; | 377         return 5; | 
| 351       case kExprF64Const: | 378       case kExprF64Const: | 
| 352         return 9; | 379         return 9; | 
|  | 380       case kExprReturn: { | 
|  | 381         ReturnArityOperand operand(this, pc); | 
|  | 382         return 1 + operand.length; | 
|  | 383       } | 
| 353 | 384 | 
| 354       default: | 385       default: | 
| 355         return 1; | 386         return 1; | 
| 356     } | 387     } | 
| 357   } | 388   } | 
| 358 }; | 389 }; | 
| 359 | 390 | 
| 360 | 391 | 
| 361 // A shift-reduce-parser strategy for decoding Wasm code that uses an explicit | 392 // A shift-reduce-parser strategy for decoding Wasm code that uses an explicit | 
| 362 // shift-reduce strategy with multiple internal stacks. | 393 // shift-reduce strategy with multiple internal stacks. | 
| 363 class SR_WasmDecoder : public WasmDecoder { | 394 class SR_WasmDecoder : public WasmDecoder { | 
| 364  public: | 395  public: | 
| 365   SR_WasmDecoder(Zone* zone, TFBuilder* builder, FunctionBody& body) | 396   SR_WasmDecoder(Zone* zone, TFBuilder* builder, FunctionBody& body) | 
| 366       : WasmDecoder(body.module, body.sig, body.start, body.end), | 397       : WasmDecoder(body.module, body.sig, body.start, body.end), | 
| 367         zone_(zone), | 398         zone_(zone), | 
| 368         builder_(builder), | 399         builder_(builder), | 
| 369         base_(body.base), | 400         base_(body.base), | 
| 370         local_type_vec_(zone), | 401         local_type_vec_(zone), | 
| 371         trees_(zone), |  | 
| 372         stack_(zone), | 402         stack_(zone), | 
| 373         blocks_(zone), | 403         control_(zone) { | 
| 374         ifs_(zone) { |  | 
| 375     local_types_ = &local_type_vec_; | 404     local_types_ = &local_type_vec_; | 
| 376   } | 405   } | 
| 377 | 406 | 
| 378   TreeResult Decode() { | 407   bool Decode() { | 
|  | 408     base::ElapsedTimer decode_timer; | 
|  | 409     if (FLAG_trace_wasm_decode_time) { | 
|  | 410       decode_timer.Start(); | 
|  | 411     } | 
|  | 412     stack_.clear(); | 
|  | 413     control_.clear(); | 
|  | 414 | 
| 379     if (end_ < pc_) { | 415     if (end_ < pc_) { | 
| 380       error(pc_, "function body end < start"); | 416       error(pc_, "function body end < start"); | 
| 381       return result_; | 417       return false; | 
| 382     } | 418     } | 
| 383 | 419 | 
| 384     DecodeLocalDecls(); | 420     DecodeLocalDecls(); | 
| 385     InitSsaEnv(); | 421     InitSsaEnv(); | 
| 386     DecodeFunctionBody(); | 422     DecodeFunctionBody(); | 
| 387 | 423 | 
| 388     Tree* tree = nullptr; | 424     if (failed()) return TraceFailed(); | 
| 389     if (ok()) { | 425 | 
| 390       if (ssa_env_->go()) { | 426     if (!control_.empty()) { | 
| 391         if (stack_.size() > 0) { | 427       error(pc_, control_.back().pc, "unterminated control structure"); | 
| 392           error(stack_.back().pc(), end_, "fell off end of code"); | 428       return TraceFailed(); | 
| 393         } |  | 
| 394         AddImplicitReturnAtEnd(); |  | 
| 395       } |  | 
| 396       if (trees_.size() == 0) { |  | 
| 397         if (sig_->return_count() > 0) { |  | 
| 398           error(start_, "no trees created"); |  | 
| 399         } |  | 
| 400       } else { |  | 
| 401         tree = trees_[0]; |  | 
| 402       } |  | 
| 403     } | 429     } | 
| 404 | 430 | 
| 405     if (ok()) { | 431     if (ssa_env_->go()) { | 
| 406       TRACE("wasm-decode ok\n"); | 432       TRACE("  @%-6d #xx:%-20s|", startrel(pc_), "ImplicitReturn"); | 
| 407     } else { | 433       DoReturn(); | 
| 408       TRACE("wasm-error module+%-6d func+%d: %s\n\n", baserel(error_pc_), | 434       if (failed()) return TraceFailed(); | 
| 409             startrel(error_pc_), error_msg_.get()); | 435       TRACE("\n"); | 
| 410     } | 436     } | 
| 411 | 437 | 
| 412     return toResult(tree); | 438     if (FLAG_trace_wasm_decode_time) { | 
|  | 439       double ms = decode_timer.Elapsed().InMillisecondsF(); | 
|  | 440       PrintF("wasm-decode ok (%0.3f ms)\n\n", ms); | 
|  | 441     } else { | 
|  | 442       TRACE("wasm-decode ok\n\n"); | 
|  | 443     } | 
|  | 444 | 
|  | 445     return true; | 
|  | 446   } | 
|  | 447 | 
|  | 448   bool TraceFailed() { | 
|  | 449     TRACE("wasm-error module+%-6d func+%d: %s\n\n", baserel(error_pc_), | 
|  | 450           startrel(error_pc_), error_msg_.get()); | 
|  | 451     return false; | 
| 413   } | 452   } | 
| 414 | 453 | 
| 415   bool DecodeLocalDecls(AstLocalDecls& decls) { | 454   bool DecodeLocalDecls(AstLocalDecls& decls) { | 
| 416     DecodeLocalDecls(); | 455     DecodeLocalDecls(); | 
| 417     if (failed()) return false; | 456     if (failed()) return false; | 
| 418     decls.decls_encoded_size = pc_offset(); | 457     decls.decls_encoded_size = pc_offset(); | 
| 419     decls.local_types.reserve(local_type_vec_.size()); | 458     decls.local_types.reserve(local_type_vec_.size()); | 
| 420     for (size_t pos = 0; pos < local_type_vec_.size();) { | 459     for (size_t pos = 0; pos < local_type_vec_.size();) { | 
| 421       uint32_t count = 0; | 460       uint32_t count = 0; | 
| 422       LocalType type = local_type_vec_[pos]; | 461       LocalType type = local_type_vec_[pos]; | 
| (...skipping 17 matching lines...) Expand all  Loading... | 
| 440     } | 479     } | 
| 441     return AnalyzeLoopAssignment(pc); | 480     return AnalyzeLoopAssignment(pc); | 
| 442   } | 481   } | 
| 443 | 482 | 
| 444  private: | 483  private: | 
| 445   static const size_t kErrorMsgSize = 128; | 484   static const size_t kErrorMsgSize = 128; | 
| 446 | 485 | 
| 447   Zone* zone_; | 486   Zone* zone_; | 
| 448   TFBuilder* builder_; | 487   TFBuilder* builder_; | 
| 449   const byte* base_; | 488   const byte* base_; | 
| 450   TreeResult result_; |  | 
| 451 | 489 | 
| 452   SsaEnv* ssa_env_; | 490   SsaEnv* ssa_env_; | 
| 453 | 491 | 
| 454   ZoneVector<LocalType> local_type_vec_; | 492   ZoneVector<LocalType> local_type_vec_; | 
| 455   ZoneVector<Tree*> trees_; | 493   ZoneVector<Value> stack_; | 
| 456   ZoneVector<Production> stack_; | 494   ZoneVector<Control> control_; | 
| 457   ZoneVector<Block> blocks_; |  | 
| 458   ZoneVector<IfEnv> ifs_; |  | 
| 459 | 495 | 
| 460   inline bool build() { return builder_ && ssa_env_->go(); } | 496   inline bool build() { return builder_ && ssa_env_->go(); } | 
| 461 | 497 | 
| 462   void InitSsaEnv() { | 498   void InitSsaEnv() { | 
| 463     TFNode* start = nullptr; | 499     TFNode* start = nullptr; | 
| 464     SsaEnv* ssa_env = reinterpret_cast<SsaEnv*>(zone_->New(sizeof(SsaEnv))); | 500     SsaEnv* ssa_env = reinterpret_cast<SsaEnv*>(zone_->New(sizeof(SsaEnv))); | 
| 465     size_t size = sizeof(TFNode*) * EnvironmentCount(); | 501     size_t size = sizeof(TFNode*) * EnvironmentCount(); | 
| 466     ssa_env->state = SsaEnv::kReached; | 502     ssa_env->state = SsaEnv::kReached; | 
| 467     ssa_env->locals = | 503     ssa_env->locals = | 
| 468         size > 0 ? reinterpret_cast<TFNode**>(zone_->New(size)) : nullptr; | 504         size > 0 ? reinterpret_cast<TFNode**>(zone_->New(size)) : nullptr; | 
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 500       case kAstF32: | 536       case kAstF32: | 
| 501         return builder_->Float32Constant(0); | 537         return builder_->Float32Constant(0); | 
| 502       case kAstF64: | 538       case kAstF64: | 
| 503         return builder_->Float64Constant(0); | 539         return builder_->Float64Constant(0); | 
| 504       default: | 540       default: | 
| 505         UNREACHABLE(); | 541         UNREACHABLE(); | 
| 506         return nullptr; | 542         return nullptr; | 
| 507     } | 543     } | 
| 508   } | 544   } | 
| 509 | 545 | 
| 510   void Leaf(LocalType type, TFNode* node = nullptr) { |  | 
| 511     size_t size = sizeof(Tree); |  | 
| 512     Tree* tree = reinterpret_cast<Tree*>(zone_->New(size)); |  | 
| 513     tree->type = type; |  | 
| 514     tree->count = 0; |  | 
| 515     tree->pc = pc_; |  | 
| 516     tree->node = node; |  | 
| 517     tree->children[0] = nullptr; |  | 
| 518     Reduce(tree); |  | 
| 519   } |  | 
| 520 |  | 
| 521   void Shift(LocalType type, uint32_t count) { |  | 
| 522     size_t size = |  | 
| 523         sizeof(Tree) + (count == 0 ? 0 : ((count - 1) * sizeof(Tree*))); |  | 
| 524     Tree* tree = reinterpret_cast<Tree*>(zone_->New(size)); |  | 
| 525     tree->type = type; |  | 
| 526     tree->count = count; |  | 
| 527     tree->pc = pc_; |  | 
| 528     tree->node = nullptr; |  | 
| 529     for (uint32_t i = 0; i < count; i++) tree->children[i] = nullptr; |  | 
| 530     if (count == 0) { |  | 
| 531       Production p = {tree, 0}; |  | 
| 532       Reduce(&p); |  | 
| 533       Reduce(tree); |  | 
| 534     } else { |  | 
| 535       stack_.push_back({tree, 0}); |  | 
| 536     } |  | 
| 537   } |  | 
| 538 |  | 
| 539   void Reduce(Tree* tree) { |  | 
| 540     while (true) { |  | 
| 541       if (stack_.size() == 0) { |  | 
| 542         trees_.push_back(tree); |  | 
| 543         break; |  | 
| 544       } |  | 
| 545       Production* p = &stack_.back(); |  | 
| 546       p->tree->children[p->index++] = tree; |  | 
| 547       Reduce(p); |  | 
| 548       if (p->done()) { |  | 
| 549         tree = p->tree; |  | 
| 550         stack_.pop_back(); |  | 
| 551       } else { |  | 
| 552         break; |  | 
| 553       } |  | 
| 554     } |  | 
| 555   } |  | 
| 556 |  | 
| 557   char* indentation() { | 546   char* indentation() { | 
| 558     static const int kMaxIndent = 64; | 547     static const int kMaxIndent = 64; | 
| 559     static char bytes[kMaxIndent + 1]; | 548     static char bytes[kMaxIndent + 1]; | 
| 560     for (int i = 0; i < kMaxIndent; i++) bytes[i] = ' '; | 549     for (int i = 0; i < kMaxIndent; i++) bytes[i] = ' '; | 
| 561     bytes[kMaxIndent] = 0; | 550     bytes[kMaxIndent] = 0; | 
| 562     if (stack_.size() < kMaxIndent / 2) { | 551     if (stack_.size() < kMaxIndent / 2) { | 
| 563       bytes[stack_.size() * 2] = 0; | 552       bytes[stack_.size() * 2] = 0; | 
| 564     } | 553     } | 
| 565     return bytes; | 554     return bytes; | 
| 566   } | 555   } | 
| (...skipping 30 matching lines...) Expand all  Loading... | 
| 597           break; | 586           break; | 
| 598         default: | 587         default: | 
| 599           error(pc_ - 1, "invalid local type"); | 588           error(pc_ - 1, "invalid local type"); | 
| 600           return; | 589           return; | 
| 601       } | 590       } | 
| 602       local_type_vec_.insert(local_type_vec_.end(), count, type); | 591       local_type_vec_.insert(local_type_vec_.end(), count, type); | 
| 603     } | 592     } | 
| 604     total_locals_ = local_type_vec_.size(); | 593     total_locals_ = local_type_vec_.size(); | 
| 605   } | 594   } | 
| 606 | 595 | 
| 607   // Decodes the body of a function, producing reduced trees into {result}. | 596   // Decodes the body of a function. | 
| 608   void DecodeFunctionBody() { | 597   void DecodeFunctionBody() { | 
| 609     TRACE("wasm-decode %p...%p (%d bytes) %s\n", | 598     TRACE("wasm-decode %p...%p (module+%d, %d bytes) %s\n", | 
| 610           reinterpret_cast<const void*>(start_), | 599           reinterpret_cast<const void*>(start_), | 
| 611           reinterpret_cast<const void*>(limit_), | 600           reinterpret_cast<const void*>(limit_), baserel(pc_), | 
| 612           static_cast<int>(limit_ - start_), builder_ ? "graph building" : ""); | 601           static_cast<int>(limit_ - start_), builder_ ? "graph building" : ""); | 
| 613 | 602 | 
| 614     if (pc_ >= limit_) return;  // Nothing to do. | 603     if (pc_ >= limit_) return;  // Nothing to do. | 
| 615 | 604 | 
| 616     while (true) {  // decoding loop. | 605     while (true) {  // decoding loop. | 
| 617       int len = 1; | 606       int len = 1; | 
| 618       WasmOpcode opcode = static_cast<WasmOpcode>(*pc_); | 607       WasmOpcode opcode = static_cast<WasmOpcode>(*pc_); | 
| 619       TRACE("wasm-decode module+%-6d %s func+%d: 0x%02x %s\n", baserel(pc_), | 608       TRACE("  @%-6d #%02x:%-20s|", startrel(pc_), opcode, | 
| 620             indentation(), startrel(pc_), opcode, | 609             WasmOpcodes::ShortOpcodeName(opcode)); | 
| 621             WasmOpcodes::OpcodeName(opcode)); |  | 
| 622 | 610 | 
| 623       FunctionSig* sig = WasmOpcodes::Signature(opcode); | 611       FunctionSig* sig = WasmOpcodes::Signature(opcode); | 
| 624       if (sig) { | 612       if (sig) { | 
| 625         // A simple expression with a fixed signature. | 613         // Fast case of a simple operator. | 
| 626         Shift(sig->GetReturn(), static_cast<uint32_t>(sig->parameter_count())); | 614         TFNode* node; | 
| 627         pc_ += len; | 615         switch (sig->parameter_count()) { | 
| 628         if (pc_ >= limit_) { | 616           case 1: { | 
| 629           // End of code reached or exceeded. | 617             Value val = Pop(0, sig->GetParam(0)); | 
| 630           if (pc_ > limit_ && ok()) { | 618             node = BUILD(Unop, opcode, val.node); | 
| 631             error("Beyond end of code"); | 619             break; | 
| 632           } | 620           } | 
| 633           return; | 621           case 2: { | 
|  | 622             Value rval = Pop(1, sig->GetParam(1)); | 
|  | 623             Value lval = Pop(0, sig->GetParam(0)); | 
|  | 624             node = BUILD(Binop, opcode, lval.node, rval.node); | 
|  | 625             break; | 
|  | 626           } | 
|  | 627           default: | 
|  | 628             UNREACHABLE(); | 
|  | 629             node = nullptr; | 
|  | 630             break; | 
| 634         } | 631         } | 
| 635         continue;  // back to decoding loop. | 632         Push(GetReturnType(sig), node); | 
| 636       } | 633       } else { | 
| 637 | 634         // Complex bytecode. | 
| 638       switch (opcode) { | 635         switch (opcode) { | 
| 639         case kExprNop: | 636           case kExprNop: | 
| 640           Leaf(kAstStmt); | 637             Push(kAstStmt, nullptr); | 
| 641           break; | 638             break; | 
| 642         case kExprBlock: { | 639           case kExprBlock: { | 
| 643           BlockCountOperand operand(this, pc_); |  | 
| 644           if (operand.count < 1) { |  | 
| 645             Leaf(kAstStmt); |  | 
| 646           } else { |  | 
| 647             Shift(kAstEnd, operand.count); |  | 
| 648             // The break environment is the outer environment. | 640             // The break environment is the outer environment. | 
| 649             SsaEnv* break_env = ssa_env_; | 641             SsaEnv* break_env = ssa_env_; | 
| 650             PushBlock(break_env); | 642             PushBlock(break_env); | 
| 651             SetEnv("block:start", Steal(break_env)); | 643             SetEnv("block:start", Steal(break_env)); | 
|  | 644             break; | 
| 652           } | 645           } | 
| 653           len = 1 + operand.length; | 646           case kExprLoop: { | 
| 654           break; |  | 
| 655         } |  | 
| 656         case kExprLoop: { |  | 
| 657           BlockCountOperand operand(this, pc_); |  | 
| 658           if (operand.count < 1) { |  | 
| 659             Leaf(kAstStmt); |  | 
| 660           } else { |  | 
| 661             Shift(kAstEnd, operand.count); |  | 
| 662             // The break environment is the outer environment. | 647             // The break environment is the outer environment. | 
| 663             SsaEnv* break_env = ssa_env_; | 648             SsaEnv* break_env = ssa_env_; | 
| 664             PushBlock(break_env); | 649             PushBlock(break_env); | 
| 665             SsaEnv* cont_env = Steal(break_env); | 650             SsaEnv* cont_env = Steal(break_env); | 
| 666             // The continue environment is the inner environment. | 651             // The continue environment is the inner environment. | 
| 667             PrepareForLoop(pc_, cont_env); | 652             PrepareForLoop(pc_, cont_env); | 
| 668             SetEnv("loop:start", Split(cont_env)); | 653             SetEnv("loop:start", Split(cont_env)); | 
| 669             if (ssa_env_->go()) ssa_env_->state = SsaEnv::kReached; | 654             ssa_env_->SetNotMerged(); | 
| 670             PushBlock(cont_env); | 655             PushLoop(cont_env); | 
| 671             blocks_.back().stack_depth = -1;  // no production for inner block. | 656             break; | 
| 672           } | 657           } | 
| 673           len = 1 + operand.length; | 658           case kExprIf: { | 
| 674           break; | 659             // Condition on top of stack. Split environments for branches. | 
|  | 660             Value cond = Pop(0, kAstI32); | 
|  | 661             TFNode* if_true = nullptr; | 
|  | 662             TFNode* if_false = nullptr; | 
|  | 663             BUILD(Branch, cond.node, &if_true, &if_false); | 
|  | 664             SsaEnv* end_env = ssa_env_; | 
|  | 665             SsaEnv* false_env = Split(ssa_env_); | 
|  | 666             false_env->control = if_false; | 
|  | 667             SsaEnv* true_env = Steal(ssa_env_); | 
|  | 668             true_env->control = if_true; | 
|  | 669             PushIf(end_env, false_env); | 
|  | 670             SetEnv("if:true", true_env); | 
|  | 671             break; | 
|  | 672           } | 
|  | 673           case kExprElse: { | 
|  | 674             if (control_.empty()) { | 
|  | 675               error(pc_, "else does not match any if"); | 
|  | 676               break; | 
|  | 677             } | 
|  | 678             Control* c = &control_.back(); | 
|  | 679             if (!c->is_if()) { | 
|  | 680               error(pc_, c->pc, "else does not match an if"); | 
|  | 681               break; | 
|  | 682             } | 
|  | 683             if (c->false_env == nullptr) { | 
|  | 684               error(pc_, c->pc, "else already present for if"); | 
|  | 685               break; | 
|  | 686             } | 
|  | 687             Value val = PopUpTo(c->stack_depth); | 
|  | 688             MergeInto(c->end_env, &c->node, &c->type, val); | 
|  | 689             // Switch to environment for false branch. | 
|  | 690             SetEnv("if_else:false", c->false_env); | 
|  | 691             c->false_env = nullptr;  // record that an else is already seen | 
|  | 692             break; | 
|  | 693           } | 
|  | 694           case kExprEnd: { | 
|  | 695             if (control_.empty()) { | 
|  | 696               error(pc_, "end does not match any if or block"); | 
|  | 697               break; | 
|  | 698             } | 
|  | 699             const char* name = "block:end"; | 
|  | 700             Control* c = &control_.back(); | 
|  | 701             if (c->is_loop) { | 
|  | 702               // Loops always push control in pairs. | 
|  | 703               control_.pop_back(); | 
|  | 704               c = &control_.back(); | 
|  | 705               name = "loop:end"; | 
|  | 706             } | 
|  | 707             Value val = PopUpTo(c->stack_depth); | 
|  | 708             if (c->is_if()) { | 
|  | 709               if (c->false_env != nullptr) { | 
|  | 710                 // End the true branch of a one-armed if. | 
|  | 711                 Goto(c->false_env, c->end_env); | 
|  | 712                 val = {val.pc, nullptr, kAstStmt}; | 
|  | 713                 name = "if:merge"; | 
|  | 714               } else { | 
|  | 715                 // End the false branch of a two-armed if. | 
|  | 716                 name = "if_else:merge"; | 
|  | 717               } | 
|  | 718             } | 
|  | 719             if (ssa_env_->go()) { | 
|  | 720               MergeInto(c->end_env, &c->node, &c->type, val); | 
|  | 721             } | 
|  | 722             SetEnv(name, c->end_env); | 
|  | 723             stack_.resize(c->stack_depth); | 
|  | 724             Push(c->type, c->node); | 
|  | 725             control_.pop_back(); | 
|  | 726             break; | 
|  | 727           } | 
|  | 728           case kExprSelect: { | 
|  | 729             Value cond = Pop(2, kAstI32); | 
|  | 730             Value fval = Pop(); | 
|  | 731             Value tval = Pop(); | 
|  | 732             if (tval.type == kAstStmt || tval.type != fval.type) { | 
|  | 733               if (tval.type != kAstEnd && fval.type != kAstEnd) { | 
|  | 734                 error(pc_, "type mismatch in select"); | 
|  | 735                 break; | 
|  | 736               } | 
|  | 737             } | 
|  | 738             if (build()) { | 
|  | 739               DCHECK(tval.type != kAstEnd); | 
|  | 740               DCHECK(fval.type != kAstEnd); | 
|  | 741               DCHECK(cond.type != kAstEnd); | 
|  | 742               TFNode* controls[2]; | 
|  | 743               builder_->Branch(cond.node, &controls[0], &controls[1]); | 
|  | 744               TFNode* merge = builder_->Merge(2, controls); | 
|  | 745               TFNode* vals[2] = {tval.node, fval.node}; | 
|  | 746               TFNode* phi = builder_->Phi(tval.type, 2, vals, merge); | 
|  | 747               Push(tval.type, phi); | 
|  | 748               ssa_env_->control = merge; | 
|  | 749             } else { | 
|  | 750               Push(tval.type, nullptr); | 
|  | 751             } | 
|  | 752             break; | 
|  | 753           } | 
|  | 754           case kExprBr: { | 
|  | 755             BreakDepthOperand operand(this, pc_); | 
|  | 756             Value val = {pc_, nullptr, kAstStmt}; | 
|  | 757             if (operand.arity) val = Pop(); | 
|  | 758             if (Validate(pc_, operand, control_)) { | 
|  | 759               BreakTo(operand.target, val); | 
|  | 760             } | 
|  | 761             len = 1 + operand.length; | 
|  | 762             Push(kAstEnd, nullptr); | 
|  | 763             break; | 
|  | 764           } | 
|  | 765           case kExprBrIf: { | 
|  | 766             BreakDepthOperand operand(this, pc_); | 
|  | 767             Value cond = Pop(operand.arity, kAstI32); | 
|  | 768             Value val = {pc_, nullptr, kAstStmt}; | 
|  | 769             if (operand.arity == 1) val = Pop(); | 
|  | 770             if (Validate(pc_, operand, control_)) { | 
|  | 771               SsaEnv* fenv = ssa_env_; | 
|  | 772               SsaEnv* tenv = Split(fenv); | 
|  | 773               fenv->SetNotMerged(); | 
|  | 774               BUILD(Branch, cond.node, &tenv->control, &fenv->control); | 
|  | 775               ssa_env_ = tenv; | 
|  | 776               BreakTo(operand.target, val); | 
|  | 777               ssa_env_ = fenv; | 
|  | 778             } | 
|  | 779             len = 1 + operand.length; | 
|  | 780             Push(kAstStmt, nullptr); | 
|  | 781             break; | 
|  | 782           } | 
|  | 783           case kExprBrTable: { | 
|  | 784             BranchTableOperand operand(this, pc_); | 
|  | 785             if (Validate(pc_, operand, control_.size())) { | 
|  | 786               Value key = Pop(operand.arity, kAstI32); | 
|  | 787               Value val = {pc_, nullptr, kAstStmt}; | 
|  | 788               if (operand.arity == 1) val = Pop(); | 
|  | 789               if (failed()) break; | 
|  | 790 | 
|  | 791               SsaEnv* break_env = ssa_env_; | 
|  | 792               if (operand.table_count > 0) { | 
|  | 793                 // Build branches to the various blocks based on the table. | 
|  | 794                 TFNode* sw = BUILD(Switch, operand.table_count + 1, key.node); | 
|  | 795 | 
|  | 796                 SsaEnv* copy = Steal(break_env); | 
|  | 797                 ssa_env_ = copy; | 
|  | 798                 for (uint32_t i = 0; i < operand.table_count + 1; i++) { | 
|  | 799                   uint16_t target = operand.read_entry(this, i); | 
|  | 800                   ssa_env_ = Split(copy); | 
|  | 801                   ssa_env_->control = (i == operand.table_count) | 
|  | 802                                           ? BUILD(IfDefault, sw) | 
|  | 803                                           : BUILD(IfValue, i, sw); | 
|  | 804                   int depth = target; | 
|  | 805                   Control* c = &control_[control_.size() - depth - 1]; | 
|  | 806                   MergeInto(c->end_env, &c->node, &c->type, val); | 
|  | 807                 } | 
|  | 808               } else { | 
|  | 809                 // Only a default target. Do the equivalent of br. | 
|  | 810                 uint16_t target = operand.read_entry(this, 0); | 
|  | 811                 int depth = target; | 
|  | 812                 Control* c = &control_[control_.size() - depth - 1]; | 
|  | 813                 MergeInto(c->end_env, &c->node, &c->type, val); | 
|  | 814               } | 
|  | 815               // br_table ends the control flow like br. | 
|  | 816               ssa_env_ = break_env; | 
|  | 817               Push(kAstStmt, nullptr); | 
|  | 818             } | 
|  | 819             len = 1 + operand.length; | 
|  | 820             break; | 
|  | 821           } | 
|  | 822           case kExprReturn: { | 
|  | 823             ReturnArityOperand operand(this, pc_); | 
|  | 824             if (operand.arity != sig_->return_count()) { | 
|  | 825               error(pc_, pc_ + 1, "arity mismatch in return"); | 
|  | 826             } | 
|  | 827             DoReturn(); | 
|  | 828             len = 1 + operand.length; | 
|  | 829             break; | 
|  | 830           } | 
|  | 831           case kExprUnreachable: { | 
|  | 832             // TODO(clemensh): add source position for unreachable | 
|  | 833             Push(kAstEnd, BUILD0(Unreachable)); | 
|  | 834             ssa_env_->Kill(SsaEnv::kControlEnd); | 
|  | 835             break; | 
|  | 836           } | 
|  | 837           case kExprI8Const: { | 
|  | 838             ImmI8Operand operand(this, pc_); | 
|  | 839             Push(kAstI32, BUILD(Int32Constant, operand.value)); | 
|  | 840             len = 1 + operand.length; | 
|  | 841             break; | 
|  | 842           } | 
|  | 843           case kExprI32Const: { | 
|  | 844             ImmI32Operand operand(this, pc_); | 
|  | 845             Push(kAstI32, BUILD(Int32Constant, operand.value)); | 
|  | 846             len = 1 + operand.length; | 
|  | 847             break; | 
|  | 848           } | 
|  | 849           case kExprI64Const: { | 
|  | 850             ImmI64Operand operand(this, pc_); | 
|  | 851             Push(kAstI64, BUILD(Int64Constant, operand.value)); | 
|  | 852             len = 1 + operand.length; | 
|  | 853             break; | 
|  | 854           } | 
|  | 855           case kExprF32Const: { | 
|  | 856             ImmF32Operand operand(this, pc_); | 
|  | 857             Push(kAstF32, BUILD(Float32Constant, operand.value)); | 
|  | 858             len = 1 + operand.length; | 
|  | 859             break; | 
|  | 860           } | 
|  | 861           case kExprF64Const: { | 
|  | 862             ImmF64Operand operand(this, pc_); | 
|  | 863             Push(kAstF64, BUILD(Float64Constant, operand.value)); | 
|  | 864             len = 1 + operand.length; | 
|  | 865             break; | 
|  | 866           } | 
|  | 867           case kExprGetLocal: { | 
|  | 868             LocalIndexOperand operand(this, pc_); | 
|  | 869             if (Validate(pc_, operand)) { | 
|  | 870               if (build()) { | 
|  | 871                 Push(operand.type, ssa_env_->locals[operand.index]); | 
|  | 872               } else { | 
|  | 873                 Push(operand.type, nullptr); | 
|  | 874               } | 
|  | 875             } | 
|  | 876             len = 1 + operand.length; | 
|  | 877             break; | 
|  | 878           } | 
|  | 879           case kExprSetLocal: { | 
|  | 880             LocalIndexOperand operand(this, pc_); | 
|  | 881             if (Validate(pc_, operand)) { | 
|  | 882               Value val = Pop(0, local_type_vec_[operand.index]); | 
|  | 883               if (ssa_env_->locals) ssa_env_->locals[operand.index] = val.node; | 
|  | 884               Push(val.type, val.node); | 
|  | 885             } | 
|  | 886             len = 1 + operand.length; | 
|  | 887             break; | 
|  | 888           } | 
|  | 889           case kExprLoadGlobal: { | 
|  | 890             GlobalIndexOperand operand(this, pc_); | 
|  | 891             if (Validate(pc_, operand)) { | 
|  | 892               Push(operand.type, BUILD(LoadGlobal, operand.index)); | 
|  | 893             } | 
|  | 894             len = 1 + operand.length; | 
|  | 895             break; | 
|  | 896           } | 
|  | 897           case kExprStoreGlobal: { | 
|  | 898             GlobalIndexOperand operand(this, pc_); | 
|  | 899             if (Validate(pc_, operand)) { | 
|  | 900               Value val = Pop(0, operand.type); | 
|  | 901               BUILD(StoreGlobal, operand.index, val.node); | 
|  | 902               Push(val.type, val.node); | 
|  | 903             } | 
|  | 904             len = 1 + operand.length; | 
|  | 905             break; | 
|  | 906           } | 
|  | 907           case kExprI32LoadMem8S: | 
|  | 908             len = DecodeLoadMem(kAstI32, MachineType::Int8()); | 
|  | 909             break; | 
|  | 910           case kExprI32LoadMem8U: | 
|  | 911             len = DecodeLoadMem(kAstI32, MachineType::Uint8()); | 
|  | 912             break; | 
|  | 913           case kExprI32LoadMem16S: | 
|  | 914             len = DecodeLoadMem(kAstI32, MachineType::Int16()); | 
|  | 915             break; | 
|  | 916           case kExprI32LoadMem16U: | 
|  | 917             len = DecodeLoadMem(kAstI32, MachineType::Uint16()); | 
|  | 918             break; | 
|  | 919           case kExprI32LoadMem: | 
|  | 920             len = DecodeLoadMem(kAstI32, MachineType::Int32()); | 
|  | 921             break; | 
|  | 922 | 
|  | 923           case kExprI64LoadMem8S: | 
|  | 924             len = DecodeLoadMem(kAstI64, MachineType::Int8()); | 
|  | 925             break; | 
|  | 926           case kExprI64LoadMem8U: | 
|  | 927             len = DecodeLoadMem(kAstI64, MachineType::Uint8()); | 
|  | 928             break; | 
|  | 929           case kExprI64LoadMem16S: | 
|  | 930             len = DecodeLoadMem(kAstI64, MachineType::Int16()); | 
|  | 931             break; | 
|  | 932           case kExprI64LoadMem16U: | 
|  | 933             len = DecodeLoadMem(kAstI64, MachineType::Uint16()); | 
|  | 934             break; | 
|  | 935           case kExprI64LoadMem32S: | 
|  | 936             len = DecodeLoadMem(kAstI64, MachineType::Int32()); | 
|  | 937             break; | 
|  | 938           case kExprI64LoadMem32U: | 
|  | 939             len = DecodeLoadMem(kAstI64, MachineType::Uint32()); | 
|  | 940             break; | 
|  | 941           case kExprI64LoadMem: | 
|  | 942             len = DecodeLoadMem(kAstI64, MachineType::Int64()); | 
|  | 943             break; | 
|  | 944           case kExprF32LoadMem: | 
|  | 945             len = DecodeLoadMem(kAstF32, MachineType::Float32()); | 
|  | 946             break; | 
|  | 947           case kExprF64LoadMem: | 
|  | 948             len = DecodeLoadMem(kAstF64, MachineType::Float64()); | 
|  | 949             break; | 
|  | 950           case kExprI32StoreMem8: | 
|  | 951             len = DecodeStoreMem(kAstI32, MachineType::Int8()); | 
|  | 952             break; | 
|  | 953           case kExprI32StoreMem16: | 
|  | 954             len = DecodeStoreMem(kAstI32, MachineType::Int16()); | 
|  | 955             break; | 
|  | 956           case kExprI32StoreMem: | 
|  | 957             len = DecodeStoreMem(kAstI32, MachineType::Int32()); | 
|  | 958             break; | 
|  | 959           case kExprI64StoreMem8: | 
|  | 960             len = DecodeStoreMem(kAstI64, MachineType::Int8()); | 
|  | 961             break; | 
|  | 962           case kExprI64StoreMem16: | 
|  | 963             len = DecodeStoreMem(kAstI64, MachineType::Int16()); | 
|  | 964             break; | 
|  | 965           case kExprI64StoreMem32: | 
|  | 966             len = DecodeStoreMem(kAstI64, MachineType::Int32()); | 
|  | 967             break; | 
|  | 968           case kExprI64StoreMem: | 
|  | 969             len = DecodeStoreMem(kAstI64, MachineType::Int64()); | 
|  | 970             break; | 
|  | 971           case kExprF32StoreMem: | 
|  | 972             len = DecodeStoreMem(kAstF32, MachineType::Float32()); | 
|  | 973             break; | 
|  | 974           case kExprF64StoreMem: | 
|  | 975             len = DecodeStoreMem(kAstF64, MachineType::Float64()); | 
|  | 976             break; | 
|  | 977 | 
|  | 978           case kExprMemorySize: | 
|  | 979             Push(kAstI32, BUILD(MemSize, 0)); | 
|  | 980             break; | 
|  | 981           case kExprGrowMemory: { | 
|  | 982             Value val = Pop(0, kAstI32); | 
|  | 983             USE(val);  // TODO(titzer): build node for grow memory | 
|  | 984             Push(kAstI32, BUILD(Int32Constant, 0)); | 
|  | 985             break; | 
|  | 986           } | 
|  | 987           case kExprCallFunction: { | 
|  | 988             CallFunctionOperand operand(this, pc_); | 
|  | 989             if (Validate(pc_, operand)) { | 
|  | 990               TFNode** buffer = PopArgs(operand.sig); | 
|  | 991               TFNode* call = BUILD(CallDirect, operand.index, buffer); | 
|  | 992               Push(GetReturnType(operand.sig), call); | 
|  | 993               AddSourcePosition(call, pc_); | 
|  | 994             } | 
|  | 995             len = 1 + operand.length; | 
|  | 996             break; | 
|  | 997           } | 
|  | 998           case kExprCallIndirect: { | 
|  | 999             CallIndirectOperand operand(this, pc_); | 
|  | 1000             if (Validate(pc_, operand)) { | 
|  | 1001               TFNode** buffer = PopArgs(operand.sig); | 
|  | 1002               Value index = Pop(0, kAstI32); | 
|  | 1003               if (buffer) buffer[0] = index.node; | 
|  | 1004               TFNode* call = BUILD(CallIndirect, operand.index, buffer); | 
|  | 1005               Push(GetReturnType(operand.sig), call); | 
|  | 1006               AddSourcePosition(call, pc_); | 
|  | 1007             } | 
|  | 1008             len = 1 + operand.length; | 
|  | 1009             break; | 
|  | 1010           } | 
|  | 1011           case kExprCallImport: { | 
|  | 1012             CallImportOperand operand(this, pc_); | 
|  | 1013             if (Validate(pc_, operand)) { | 
|  | 1014               TFNode** buffer = PopArgs(operand.sig); | 
|  | 1015               TFNode* call = BUILD(CallImport, operand.index, buffer); | 
|  | 1016               Push(GetReturnType(operand.sig), call); | 
|  | 1017               AddSourcePosition(call, pc_); | 
|  | 1018             } | 
|  | 1019             len = 1 + operand.length; | 
|  | 1020             break; | 
|  | 1021           } | 
|  | 1022           default: | 
|  | 1023             error("Invalid opcode"); | 
|  | 1024             return; | 
| 675         } | 1025         } | 
| 676         case kExprIf: | 1026       }  // end complex bytecode | 
| 677           Shift(kAstStmt, 2); | 1027 | 
| 678           break; | 1028 #if DEBUG | 
| 679         case kExprIfElse: | 1029       if (FLAG_trace_wasm_decoder) { | 
| 680           Shift(kAstEnd, 3);  // Result type is typeof(x) in {c ? x : y}. | 1030         for (size_t i = 0; i < stack_.size(); i++) { | 
| 681           break; | 1031           Value& val = stack_[i]; | 
| 682         case kExprSelect: | 1032           WasmOpcode opcode = static_cast<WasmOpcode>(*val.pc); | 
| 683           Shift(kAstStmt, 3);  // Result type is typeof(x) in {c ? x : y}. | 1033           PrintF(" %c@%d:%s", WasmOpcodes::ShortNameOf(val.type), | 
| 684           break; | 1034                  static_cast<int>(val.pc - start_), | 
| 685         case kExprBr: { | 1035                  WasmOpcodes::ShortOpcodeName(opcode)); | 
| 686           BreakDepthOperand operand(this, pc_); | 1036           switch (opcode) { | 
| 687           if (Validate(pc_, operand, blocks_)) { | 1037             case kExprI32Const: { | 
| 688             Shift(kAstEnd, 1); | 1038               ImmI32Operand operand(this, val.pc); | 
| 689           } | 1039               PrintF("[%d]", operand.value); | 
| 690           len = 1 + operand.length; | 1040               break; | 
| 691           break; | 1041             } | 
|  | 1042             case kExprGetLocal: { | 
|  | 1043               LocalIndexOperand operand(this, val.pc); | 
|  | 1044               PrintF("[%u]", operand.index); | 
|  | 1045               break; | 
|  | 1046             } | 
|  | 1047             case kExprSetLocal: { | 
|  | 1048               LocalIndexOperand operand(this, val.pc); | 
|  | 1049               PrintF("[%u]", operand.index); | 
|  | 1050               break; | 
|  | 1051             } | 
|  | 1052             default: | 
|  | 1053               break; | 
|  | 1054           } | 
| 692         } | 1055         } | 
| 693         case kExprBrIf: { | 1056         PrintF("\n"); | 
| 694           BreakDepthOperand operand(this, pc_); |  | 
| 695           if (Validate(pc_, operand, blocks_)) { |  | 
| 696             Shift(kAstStmt, 2); |  | 
| 697           } |  | 
| 698           len = 1 + operand.length; |  | 
| 699           break; |  | 
| 700         } |  | 
| 701         case kExprBrTable: { |  | 
| 702           BranchTableOperand operand(this, pc_); |  | 
| 703           if (Validate(pc_, operand, blocks_.size())) { |  | 
| 704             Shift(kAstEnd, 1); |  | 
| 705           } |  | 
| 706           len = 1 + operand.length; |  | 
| 707           break; |  | 
| 708         } |  | 
| 709         case kExprReturn: { |  | 
| 710           int count = static_cast<int>(sig_->return_count()); |  | 
| 711           if (count == 0) { |  | 
| 712             BUILD(Return, 0, builder_->Buffer(0)); |  | 
| 713             ssa_env_->Kill(); |  | 
| 714             Leaf(kAstEnd); |  | 
| 715           } else { |  | 
| 716             Shift(kAstEnd, count); |  | 
| 717           } |  | 
| 718           break; |  | 
| 719         } |  | 
| 720         case kExprUnreachable: { |  | 
| 721           // TODO(clemensh): add source position for unreachable |  | 
| 722           BUILD0(Unreachable); |  | 
| 723           ssa_env_->Kill(SsaEnv::kControlEnd); |  | 
| 724           Leaf(kAstEnd, nullptr); |  | 
| 725           break; |  | 
| 726         } |  | 
| 727         case kExprI8Const: { |  | 
| 728           ImmI8Operand operand(this, pc_); |  | 
| 729           Leaf(kAstI32, BUILD(Int32Constant, operand.value)); |  | 
| 730           len = 1 + operand.length; |  | 
| 731           break; |  | 
| 732         } |  | 
| 733         case kExprI32Const: { |  | 
| 734           ImmI32Operand operand(this, pc_); |  | 
| 735           Leaf(kAstI32, BUILD(Int32Constant, operand.value)); |  | 
| 736           len = 1 + operand.length; |  | 
| 737           break; |  | 
| 738         } |  | 
| 739         case kExprI64Const: { |  | 
| 740           ImmI64Operand operand(this, pc_); |  | 
| 741           Leaf(kAstI64, BUILD(Int64Constant, operand.value)); |  | 
| 742           len = 1 + operand.length; |  | 
| 743           break; |  | 
| 744         } |  | 
| 745         case kExprF32Const: { |  | 
| 746           ImmF32Operand operand(this, pc_); |  | 
| 747           Leaf(kAstF32, BUILD(Float32Constant, operand.value)); |  | 
| 748           len = 1 + operand.length; |  | 
| 749           break; |  | 
| 750         } |  | 
| 751         case kExprF64Const: { |  | 
| 752           ImmF64Operand operand(this, pc_); |  | 
| 753           Leaf(kAstF64, BUILD(Float64Constant, operand.value)); |  | 
| 754           len = 1 + operand.length; |  | 
| 755           break; |  | 
| 756         } |  | 
| 757         case kExprGetLocal: { |  | 
| 758           LocalIndexOperand operand(this, pc_); |  | 
| 759           if (Validate(pc_, operand)) { |  | 
| 760             TFNode* val = build() ? ssa_env_->locals[operand.index] : nullptr; |  | 
| 761             Leaf(operand.type, val); |  | 
| 762           } |  | 
| 763           len = 1 + operand.length; |  | 
| 764           break; |  | 
| 765         } |  | 
| 766         case kExprSetLocal: { |  | 
| 767           LocalIndexOperand operand(this, pc_); |  | 
| 768           if (Validate(pc_, operand)) { |  | 
| 769             Shift(operand.type, 1); |  | 
| 770           } |  | 
| 771           len = 1 + operand.length; |  | 
| 772           break; |  | 
| 773         } |  | 
| 774         case kExprLoadGlobal: { |  | 
| 775           GlobalIndexOperand operand(this, pc_); |  | 
| 776           if (Validate(pc_, operand)) { |  | 
| 777             Leaf(operand.type, BUILD(LoadGlobal, operand.index)); |  | 
| 778           } |  | 
| 779           len = 1 + operand.length; |  | 
| 780           break; |  | 
| 781         } |  | 
| 782         case kExprStoreGlobal: { |  | 
| 783           GlobalIndexOperand operand(this, pc_); |  | 
| 784           if (Validate(pc_, operand)) { |  | 
| 785             Shift(operand.type, 1); |  | 
| 786           } |  | 
| 787           len = 1 + operand.length; |  | 
| 788           break; |  | 
| 789         } |  | 
| 790         case kExprI32LoadMem8S: |  | 
| 791         case kExprI32LoadMem8U: |  | 
| 792         case kExprI32LoadMem16S: |  | 
| 793         case kExprI32LoadMem16U: |  | 
| 794         case kExprI32LoadMem: |  | 
| 795           len = DecodeLoadMem(pc_, kAstI32); |  | 
| 796           break; |  | 
| 797         case kExprI64LoadMem8S: |  | 
| 798         case kExprI64LoadMem8U: |  | 
| 799         case kExprI64LoadMem16S: |  | 
| 800         case kExprI64LoadMem16U: |  | 
| 801         case kExprI64LoadMem32S: |  | 
| 802         case kExprI64LoadMem32U: |  | 
| 803         case kExprI64LoadMem: |  | 
| 804           len = DecodeLoadMem(pc_, kAstI64); |  | 
| 805           break; |  | 
| 806         case kExprF32LoadMem: |  | 
| 807           len = DecodeLoadMem(pc_, kAstF32); |  | 
| 808           break; |  | 
| 809         case kExprF64LoadMem: |  | 
| 810           len = DecodeLoadMem(pc_, kAstF64); |  | 
| 811           break; |  | 
| 812         case kExprI32StoreMem8: |  | 
| 813         case kExprI32StoreMem16: |  | 
| 814         case kExprI32StoreMem: |  | 
| 815           len = DecodeStoreMem(pc_, kAstI32); |  | 
| 816           break; |  | 
| 817         case kExprI64StoreMem8: |  | 
| 818         case kExprI64StoreMem16: |  | 
| 819         case kExprI64StoreMem32: |  | 
| 820         case kExprI64StoreMem: |  | 
| 821           len = DecodeStoreMem(pc_, kAstI64); |  | 
| 822           break; |  | 
| 823         case kExprF32StoreMem: |  | 
| 824           len = DecodeStoreMem(pc_, kAstF32); |  | 
| 825           break; |  | 
| 826         case kExprF64StoreMem: |  | 
| 827           len = DecodeStoreMem(pc_, kAstF64); |  | 
| 828           break; |  | 
| 829         case kExprMemorySize: |  | 
| 830           Leaf(kAstI32, BUILD(MemSize, 0)); |  | 
| 831           break; |  | 
| 832         case kExprGrowMemory: |  | 
| 833           Shift(kAstI32, 1); |  | 
| 834           break; |  | 
| 835         case kExprCallFunction: { |  | 
| 836           FunctionIndexOperand operand(this, pc_); |  | 
| 837           if (Validate(pc_, operand)) { |  | 
| 838             LocalType type = operand.sig->return_count() == 0 |  | 
| 839                                  ? kAstStmt |  | 
| 840                                  : operand.sig->GetReturn(); |  | 
| 841             Shift(type, static_cast<int>(operand.sig->parameter_count())); |  | 
| 842           } |  | 
| 843           len = 1 + operand.length; |  | 
| 844           break; |  | 
| 845         } |  | 
| 846         case kExprCallIndirect: { |  | 
| 847           SignatureIndexOperand operand(this, pc_); |  | 
| 848           if (Validate(pc_, operand)) { |  | 
| 849             LocalType type = operand.sig->return_count() == 0 |  | 
| 850                                  ? kAstStmt |  | 
| 851                                  : operand.sig->GetReturn(); |  | 
| 852             Shift(type, static_cast<int>(1 + operand.sig->parameter_count())); |  | 
| 853           } |  | 
| 854           len = 1 + operand.length; |  | 
| 855           break; |  | 
| 856         } |  | 
| 857         case kExprCallImport: { |  | 
| 858           ImportIndexOperand operand(this, pc_); |  | 
| 859           if (Validate(pc_, operand)) { |  | 
| 860             LocalType type = operand.sig->return_count() == 0 |  | 
| 861                                  ? kAstStmt |  | 
| 862                                  : operand.sig->GetReturn(); |  | 
| 863             Shift(type, static_cast<int>(operand.sig->parameter_count())); |  | 
| 864           } |  | 
| 865           len = 1 + operand.length; |  | 
| 866           break; |  | 
| 867         } |  | 
| 868         case kExprDeclLocals: |  | 
| 869         default: |  | 
| 870           error("Invalid opcode"); |  | 
| 871           return; |  | 
| 872       } | 1057       } | 
|  | 1058 #endif | 
| 873       pc_ += len; | 1059       pc_ += len; | 
| 874       if (pc_ >= limit_) { | 1060       if (pc_ >= limit_) { | 
| 875         // End of code reached or exceeded. | 1061         // End of code reached or exceeded. | 
| 876         if (pc_ > limit_ && ok()) { | 1062         if (pc_ > limit_ && ok()) error("Beyond end of code"); | 
| 877           error("Beyond end of code"); |  | 
| 878         } |  | 
| 879         return; | 1063         return; | 
| 880       } | 1064       } | 
| 881     } | 1065     }  // end decode loop | 
| 882   } | 1066   }    // end DecodeFunctionBody() | 
| 883 | 1067 | 
| 884   void PushBlock(SsaEnv* ssa_env) { | 1068   TFNode** PopArgs(FunctionSig* sig) { | 
| 885     blocks_.push_back({ssa_env, static_cast<int>(stack_.size() - 1)}); | 1069     if (build()) { | 
| 886   } | 1070       int count = static_cast<int>(sig->parameter_count()); | 
| 887 | 1071       TFNode** buffer = builder_->Buffer(count + 1); | 
| 888   int DecodeLoadMem(const byte* pc, LocalType type) { | 1072       buffer[0] = nullptr;  // reserved for code object or function index. | 
| 889     MemoryAccessOperand operand(this, pc); | 1073       for (int i = count - 1; i >= 0; i--) { | 
| 890     Shift(type, 1); | 1074         buffer[i + 1] = Pop(i, sig->GetParam(i)).node; | 
|  | 1075       } | 
|  | 1076       return buffer; | 
|  | 1077     } else { | 
|  | 1078       int count = static_cast<int>(sig->parameter_count()); | 
|  | 1079       for (int i = count - 1; i >= 0; i--) { | 
|  | 1080         Pop(i, sig->GetParam(i)); | 
|  | 1081       } | 
|  | 1082       return nullptr; | 
|  | 1083     } | 
|  | 1084   } | 
|  | 1085 | 
|  | 1086   LocalType GetReturnType(FunctionSig* sig) { | 
|  | 1087     return sig->return_count() == 0 ? kAstStmt : sig->GetReturn(); | 
|  | 1088   } | 
|  | 1089 | 
|  | 1090   void PushBlock(SsaEnv* end_env) { | 
|  | 1091     int stack_depth = static_cast<int>(stack_.size()); | 
|  | 1092     control_.push_back( | 
|  | 1093         {pc_, stack_depth, end_env, nullptr, nullptr, kAstEnd, false}); | 
|  | 1094   } | 
|  | 1095 | 
|  | 1096   void PushLoop(SsaEnv* end_env) { | 
|  | 1097     int stack_depth = static_cast<int>(stack_.size()); | 
|  | 1098     control_.push_back( | 
|  | 1099         {pc_, stack_depth, end_env, nullptr, nullptr, kAstEnd, true}); | 
|  | 1100   } | 
|  | 1101 | 
|  | 1102   void PushIf(SsaEnv* end_env, SsaEnv* false_env) { | 
|  | 1103     int stack_depth = static_cast<int>(stack_.size()); | 
|  | 1104     control_.push_back( | 
|  | 1105         {pc_, stack_depth, end_env, false_env, nullptr, kAstStmt, false}); | 
|  | 1106   } | 
|  | 1107 | 
|  | 1108   int DecodeLoadMem(LocalType type, MachineType mem_type) { | 
|  | 1109     MemoryAccessOperand operand(this, pc_); | 
|  | 1110     Value index = Pop(0, kAstI32); | 
|  | 1111     TFNode* node = BUILD(LoadMem, type, mem_type, index.node, operand.offset); | 
|  | 1112     Push(type, node); | 
| 891     return 1 + operand.length; | 1113     return 1 + operand.length; | 
| 892   } | 1114   } | 
| 893 | 1115 | 
| 894   int DecodeStoreMem(const byte* pc, LocalType type) { | 1116   int DecodeStoreMem(LocalType type, MachineType mem_type) { | 
| 895     MemoryAccessOperand operand(this, pc); | 1117     MemoryAccessOperand operand(this, pc_); | 
| 896     Shift(type, 2); | 1118     Value val = Pop(1, type); | 
|  | 1119     Value index = Pop(0, kAstI32); | 
|  | 1120     BUILD(StoreMem, mem_type, index.node, operand.offset, val.node); | 
|  | 1121     Push(type, val.node); | 
| 897     return 1 + operand.length; | 1122     return 1 + operand.length; | 
| 898   } | 1123   } | 
| 899 | 1124 | 
| 900   void AddImplicitReturnAtEnd() { | 1125   void DoReturn() { | 
| 901     int retcount = static_cast<int>(sig_->return_count()); | 1126     int count = static_cast<int>(sig_->return_count()); | 
| 902     if (retcount == 0) { | 1127     TFNode** buffer = nullptr; | 
| 903       BUILD0(ReturnVoid); | 1128     if (build()) buffer = builder_->Buffer(count); | 
| 904       return; | 1129 | 
| 905     } | 1130     // Pop return values off the stack in reverse order. | 
| 906 | 1131     for (int i = count - 1; i >= 0; i--) { | 
| 907     if (static_cast<int>(trees_.size()) < retcount) { | 1132       Value val = Pop(i, sig_->GetReturn(i)); | 
| 908       error(limit_, nullptr, | 1133       if (buffer) buffer[i] = val.node; | 
| 909             "ImplicitReturn expects %d arguments, only %d remain", retcount, | 1134     } | 
| 910             static_cast<int>(trees_.size())); | 1135 | 
| 911       return; | 1136     Push(kAstEnd, BUILD(Return, count, buffer)); | 
| 912     } | 1137     ssa_env_->Kill(SsaEnv::kControlEnd); | 
| 913 | 1138   } | 
| 914     TRACE("wasm-decode implicit return of %d args\n", retcount); | 1139 | 
| 915 | 1140   void Push(LocalType type, TFNode* node) { | 
| 916     TFNode** buffer = BUILD(Buffer, retcount); | 1141     stack_.push_back({pc_, node, type}); | 
| 917     for (int index = 0; index < retcount; index++) { | 1142   } | 
| 918       Tree* tree = trees_[trees_.size() - 1 - index]; | 1143 | 
| 919       if (buffer) buffer[index] = tree->node; | 1144   const char* SafeOpcodeNameAt(const byte* pc) { | 
| 920       LocalType expected = sig_->GetReturn(index); | 1145     if (pc >= end_) return "<end>"; | 
| 921       if (tree->type != expected) { | 1146     return WasmOpcodes::ShortOpcodeName(static_cast<WasmOpcode>(*pc)); | 
| 922         error(limit_, tree->pc, | 1147   } | 
| 923               "ImplicitReturn[%d] expected type %s, found %s of type %s", index, | 1148 | 
| 924               WasmOpcodes::TypeName(expected), | 1149   Value Pop(int index, LocalType expected) { | 
| 925               WasmOpcodes::OpcodeName(tree->opcode()), | 1150     Value val = Pop(); | 
| 926               WasmOpcodes::TypeName(tree->type)); | 1151     if (val.type != expected) { | 
| 927         return; | 1152       if (val.type != kAstEnd) { | 
|  | 1153         error(pc_, val.pc, "%s[%d] expected type %s, found %s of type %s", | 
|  | 1154               SafeOpcodeNameAt(pc_), index, WasmOpcodes::TypeName(expected), | 
|  | 1155               SafeOpcodeNameAt(val.pc), WasmOpcodes::TypeName(val.type)); | 
| 928       } | 1156       } | 
| 929     } | 1157     } | 
| 930 | 1158     return val; | 
| 931     BUILD(Return, retcount, buffer); | 1159   } | 
|  | 1160 | 
|  | 1161   Value Pop() { | 
|  | 1162     if (stack_.empty()) { | 
|  | 1163       Value val = {pc_, nullptr, kAstStmt}; | 
|  | 1164       error(pc_, pc_, "%s found empty stack", SafeOpcodeNameAt(pc_)); | 
|  | 1165       return val; | 
|  | 1166     } | 
|  | 1167     Value val = stack_.back(); | 
|  | 1168     stack_.pop_back(); | 
|  | 1169     return val; | 
|  | 1170   } | 
|  | 1171 | 
|  | 1172   Value PopUpTo(int stack_depth) { | 
|  | 1173     if (stack_depth == stack_.size()) { | 
|  | 1174       Value val = {pc_, nullptr, kAstStmt}; | 
|  | 1175       return val; | 
|  | 1176     } else { | 
|  | 1177       DCHECK_LE(stack_depth, static_cast<int>(stack_.size())); | 
|  | 1178       Value val = Pop(); | 
|  | 1179       stack_.resize(stack_depth); | 
|  | 1180       return val; | 
|  | 1181     } | 
| 932   } | 1182   } | 
| 933 | 1183 | 
| 934   int baserel(const byte* ptr) { | 1184   int baserel(const byte* ptr) { | 
| 935     return base_ ? static_cast<int>(ptr - base_) : 0; | 1185     return base_ ? static_cast<int>(ptr - base_) : 0; | 
| 936   } | 1186   } | 
| 937 | 1187 | 
| 938   int startrel(const byte* ptr) { return static_cast<int>(ptr - start_); } | 1188   int startrel(const byte* ptr) { return static_cast<int>(ptr - start_); } | 
| 939 | 1189 | 
| 940   void Reduce(Production* p) { | 1190   void BreakTo(Control* block, Value& val) { | 
| 941     WasmOpcode opcode = p->opcode(); | 1191     if (block->is_loop) { | 
| 942     TRACE("-----reduce module+%-6d %s func+%d: 0x%02x %s\n", baserel(p->pc()), | 1192       // This is the inner loop block, which does not have a value. | 
| 943           indentation(), startrel(p->pc()), opcode, | 1193       Goto(ssa_env_, block->end_env); | 
| 944           WasmOpcodes::OpcodeName(opcode)); | 1194     } else { | 
| 945     FunctionSig* sig = WasmOpcodes::Signature(opcode); | 1195       // Merge the value into the production for the block. | 
| 946     if (sig) { | 1196       MergeInto(block->end_env, &block->node, &block->type, val); | 
| 947       // A simple expression with a fixed signature. | 1197     } | 
| 948       TypeCheckLast(p, sig->GetParam(p->index - 1)); | 1198   } | 
| 949       if (p->done() && build()) { | 1199 | 
| 950         if (sig->parameter_count() == 2) { | 1200   void MergeInto(SsaEnv* target, TFNode** node, LocalType* type, Value& val) { | 
| 951           p->tree->node = builder_->Binop(opcode, p->tree->children[0]->node, | 1201     if (!ssa_env_->go()) return; | 
| 952                                           p->tree->children[1]->node); | 1202     DCHECK_NE(kAstEnd, val.type); | 
| 953         } else if (sig->parameter_count() == 1) { | 1203 | 
| 954           p->tree->node = builder_->Unop(opcode, p->tree->children[0]->node); | 1204     bool first = target->state == SsaEnv::kUnreachable; | 
| 955         } else { | 1205     Goto(ssa_env_, target); | 
| 956           UNREACHABLE(); | 1206 | 
|  | 1207     if (first) { | 
|  | 1208       // first merge to this environment; set the type and the node. | 
|  | 1209       *type = val.type; | 
|  | 1210       *node = val.node; | 
|  | 1211     } else if (val.type == *type && val.type != kAstStmt) { | 
|  | 1212       // merge with the existing value for this block. | 
|  | 1213       *node = CreateOrMergeIntoPhi(*type, target->control, *node, val.node); | 
|  | 1214     } else { | 
|  | 1215       // types don't match, or block is already a stmt. | 
|  | 1216       *type = kAstStmt; | 
|  | 1217       *node = nullptr; | 
|  | 1218     } | 
|  | 1219   } | 
|  | 1220 | 
|  | 1221   void SetEnv(const char* reason, SsaEnv* env) { | 
|  | 1222 #if DEBUG | 
|  | 1223     if (FLAG_trace_wasm_decoder) { | 
|  | 1224       char state = 'X'; | 
|  | 1225       if (env) { | 
|  | 1226         switch (env->state) { | 
|  | 1227           case SsaEnv::kReached: | 
|  | 1228             state = 'R'; | 
|  | 1229             break; | 
|  | 1230           case SsaEnv::kUnreachable: | 
|  | 1231             state = 'U'; | 
|  | 1232             break; | 
|  | 1233           case SsaEnv::kMerged: | 
|  | 1234             state = 'M'; | 
|  | 1235             break; | 
|  | 1236           case SsaEnv::kControlEnd: | 
|  | 1237             state = 'E'; | 
|  | 1238             break; | 
| 957         } | 1239         } | 
| 958       } | 1240       } | 
| 959       return; | 1241       PrintF("  env = %p, state = %c, reason = %s", static_cast<void*>(env), | 
| 960     } | 1242              state, reason); | 
| 961 | 1243       if (env && env->control) { | 
| 962     switch (opcode) { | 1244         PrintF(", control = "); | 
| 963       case kExprBlock: { | 1245         compiler::WasmGraphBuilder::PrintDebugName(env->control); | 
| 964         if (p->done()) { |  | 
| 965           Block* last = &blocks_.back(); |  | 
| 966           DCHECK_EQ(stack_.size() - 1, last->stack_depth); |  | 
| 967           // fallthrough with the last expression. |  | 
| 968           ReduceBreakToExprBlock(p, last); |  | 
| 969           SetEnv("block:end", last->ssa_env); |  | 
| 970           blocks_.pop_back(); |  | 
| 971         } |  | 
| 972         break; |  | 
| 973       } | 1246       } | 
| 974       case kExprLoop: { | 1247       PrintF("\n"); | 
| 975         if (p->done()) { | 1248     } | 
| 976           // Pop the continue environment. |  | 
| 977           blocks_.pop_back(); |  | 
| 978           // Get the break environment. |  | 
| 979           Block* last = &blocks_.back(); |  | 
| 980           DCHECK_EQ(stack_.size() - 1, last->stack_depth); |  | 
| 981           // fallthrough with the last expression. |  | 
| 982           ReduceBreakToExprBlock(p, last); |  | 
| 983           SetEnv("loop:end", last->ssa_env); |  | 
| 984           blocks_.pop_back(); |  | 
| 985         } |  | 
| 986         break; |  | 
| 987       } |  | 
| 988       case kExprIf: { |  | 
| 989         if (p->index == 1) { |  | 
| 990           // Condition done. Split environment for true branch. |  | 
| 991           TypeCheckLast(p, kAstI32); |  | 
| 992           SsaEnv* false_env = ssa_env_; |  | 
| 993           SsaEnv* true_env = Split(ssa_env_); |  | 
| 994           ifs_.push_back({nullptr, false_env, nullptr}); |  | 
| 995           BUILD(Branch, p->last()->node, &true_env->control, |  | 
| 996                 &false_env->control); |  | 
| 997           SetEnv("if:true", true_env); |  | 
| 998         } else if (p->index == 2) { |  | 
| 999           // True block done. Merge true and false environments. |  | 
| 1000           IfEnv* env = &ifs_.back(); |  | 
| 1001           SsaEnv* merge = env->merge_env; |  | 
| 1002           if (merge->go()) { |  | 
| 1003             merge->state = SsaEnv::kReached; |  | 
| 1004             Goto(ssa_env_, merge); |  | 
| 1005           } |  | 
| 1006           SetEnv("if:merge", merge); |  | 
| 1007           ifs_.pop_back(); |  | 
| 1008         } |  | 
| 1009         break; |  | 
| 1010       } |  | 
| 1011       case kExprIfElse: { |  | 
| 1012         if (p->index == 1) { |  | 
| 1013           // Condition done. Split environment for true and false branches. |  | 
| 1014           TypeCheckLast(p, kAstI32); |  | 
| 1015           SsaEnv* merge_env = ssa_env_; |  | 
| 1016           TFNode* if_true = nullptr; |  | 
| 1017           TFNode* if_false = nullptr; |  | 
| 1018           BUILD(Branch, p->last()->node, &if_true, &if_false); |  | 
| 1019           SsaEnv* false_env = Split(ssa_env_); |  | 
| 1020           SsaEnv* true_env = Steal(ssa_env_); |  | 
| 1021           false_env->control = if_false; |  | 
| 1022           true_env->control = if_true; |  | 
| 1023           ifs_.push_back({false_env, merge_env, nullptr}); |  | 
| 1024           SetEnv("if_else:true", true_env); |  | 
| 1025         } else if (p->index == 2) { |  | 
| 1026           // True expr done. |  | 
| 1027           IfEnv* env = &ifs_.back(); |  | 
| 1028           MergeIntoProduction(p, env->merge_env, p->last()); |  | 
| 1029           // Switch to environment for false branch. |  | 
| 1030           SsaEnv* false_env = ifs_.back().false_env; |  | 
| 1031           SetEnv("if_else:false", false_env); |  | 
| 1032         } else if (p->index == 3) { |  | 
| 1033           // False expr done. |  | 
| 1034           IfEnv* env = &ifs_.back(); |  | 
| 1035           MergeIntoProduction(p, env->merge_env, p->last()); |  | 
| 1036           SetEnv("if_else:merge", env->merge_env); |  | 
| 1037           ifs_.pop_back(); |  | 
| 1038         } |  | 
| 1039         break; |  | 
| 1040       } |  | 
| 1041       case kExprSelect: { |  | 
| 1042         if (p->index == 1) { |  | 
| 1043           // True expression done. |  | 
| 1044           p->tree->type = p->last()->type; |  | 
| 1045           if (p->tree->type == kAstStmt) { |  | 
| 1046             error(p->pc(), p->tree->children[1]->pc, |  | 
| 1047                   "select operand should be expression"); |  | 
| 1048           } |  | 
| 1049         } else if (p->index == 2) { |  | 
| 1050           // False expression done. |  | 
| 1051           TypeCheckLast(p, p->tree->type); |  | 
| 1052         } else { |  | 
| 1053           // Condition done. |  | 
| 1054           DCHECK(p->done()); |  | 
| 1055           TypeCheckLast(p, kAstI32); |  | 
| 1056           if (build()) { |  | 
| 1057             TFNode* controls[2]; |  | 
| 1058             builder_->Branch(p->tree->children[2]->node, &controls[0], |  | 
| 1059                              &controls[1]); |  | 
| 1060             TFNode* merge = builder_->Merge(2, controls); |  | 
| 1061             TFNode* vals[2] = {p->tree->children[0]->node, |  | 
| 1062                                p->tree->children[1]->node}; |  | 
| 1063             TFNode* phi = builder_->Phi(p->tree->type, 2, vals, merge); |  | 
| 1064             p->tree->node = phi; |  | 
| 1065             ssa_env_->control = merge; |  | 
| 1066           } |  | 
| 1067         } |  | 
| 1068         break; |  | 
| 1069       } |  | 
| 1070       case kExprBr: { |  | 
| 1071         BreakDepthOperand operand(this, p->pc()); |  | 
| 1072         CHECK(Validate(p->pc(), operand, blocks_)); |  | 
| 1073         ReduceBreakToExprBlock(p, operand.target); |  | 
| 1074         break; |  | 
| 1075       } |  | 
| 1076       case kExprBrIf: { |  | 
| 1077         if (p->done()) { |  | 
| 1078           TypeCheckLast(p, kAstI32); |  | 
| 1079           BreakDepthOperand operand(this, p->pc()); |  | 
| 1080           CHECK(Validate(p->pc(), operand, blocks_)); |  | 
| 1081           SsaEnv* fenv = ssa_env_; |  | 
| 1082           SsaEnv* tenv = Split(fenv); |  | 
| 1083           BUILD(Branch, p->tree->children[1]->node, &tenv->control, |  | 
| 1084                 &fenv->control); |  | 
| 1085           ssa_env_ = tenv; |  | 
| 1086           ReduceBreakToExprBlock(p, operand.target, p->tree->children[0]); |  | 
| 1087           ssa_env_ = fenv; |  | 
| 1088         } |  | 
| 1089         break; |  | 
| 1090       } |  | 
| 1091       case kExprBrTable: { |  | 
| 1092         if (p->index == 1) { |  | 
| 1093           // Switch key finished. |  | 
| 1094           TypeCheckLast(p, kAstI32); |  | 
| 1095           if (failed()) break; |  | 
| 1096 |  | 
| 1097           BranchTableOperand operand(this, p->pc()); |  | 
| 1098           DCHECK(Validate(p->pc(), operand, blocks_.size())); |  | 
| 1099 |  | 
| 1100           // Build a switch only if it has more than just a default target. |  | 
| 1101           bool build_switch = operand.table_count > 0; |  | 
| 1102           TFNode* sw = nullptr; |  | 
| 1103           if (build_switch) { |  | 
| 1104             sw = BUILD(Switch, operand.table_count + 1, p->last()->node); |  | 
| 1105           } |  | 
| 1106 |  | 
| 1107           // Process the targets of the break table. |  | 
| 1108           SsaEnv* prev = ssa_env_; |  | 
| 1109           SsaEnv* copy = Steal(prev); |  | 
| 1110           for (uint32_t i = 0; i < operand.table_count + 1; i++) { |  | 
| 1111             uint32_t target = operand.read_entry(this, i); |  | 
| 1112             SsaEnv* env = copy; |  | 
| 1113             if (build_switch) { |  | 
| 1114               ssa_env_ = env = Split(env); |  | 
| 1115               env->control = i == operand.table_count ? BUILD(IfDefault, sw) |  | 
| 1116                                                       : BUILD(IfValue, i, sw); |  | 
| 1117             } |  | 
| 1118             SsaEnv* tenv = blocks_[blocks_.size() - target - 1].ssa_env; |  | 
| 1119             Goto(env, tenv); |  | 
| 1120           } |  | 
| 1121           ssa_env_ = prev; |  | 
| 1122         } |  | 
| 1123         break; |  | 
| 1124       } |  | 
| 1125       case kExprReturn: { |  | 
| 1126         TypeCheckLast(p, sig_->GetReturn(p->index - 1)); |  | 
| 1127         if (p->done()) { |  | 
| 1128           if (build()) { |  | 
| 1129             int count = p->tree->count; |  | 
| 1130             TFNode** buffer = builder_->Buffer(count); |  | 
| 1131             for (int i = 0; i < count; i++) { |  | 
| 1132               buffer[i] = p->tree->children[i]->node; |  | 
| 1133             } |  | 
| 1134             BUILD(Return, count, buffer); |  | 
| 1135           } |  | 
| 1136           ssa_env_->Kill(SsaEnv::kControlEnd); |  | 
| 1137         } |  | 
| 1138         break; |  | 
| 1139       } |  | 
| 1140       case kExprSetLocal: { |  | 
| 1141         LocalIndexOperand operand(this, p->pc()); |  | 
| 1142         CHECK(Validate(p->pc(), operand)); |  | 
| 1143         Tree* val = p->last(); |  | 
| 1144         if (operand.type == val->type) { |  | 
| 1145           if (build()) ssa_env_->locals[operand.index] = val->node; |  | 
| 1146           p->tree->node = val->node; |  | 
| 1147         } else { |  | 
| 1148           error(p->pc(), val->pc, "Typecheck failed in SetLocal"); |  | 
| 1149         } |  | 
| 1150         break; |  | 
| 1151       } |  | 
| 1152       case kExprStoreGlobal: { |  | 
| 1153         GlobalIndexOperand operand(this, p->pc()); |  | 
| 1154         CHECK(Validate(p->pc(), operand)); |  | 
| 1155         Tree* val = p->last(); |  | 
| 1156         if (operand.type == val->type) { |  | 
| 1157           BUILD(StoreGlobal, operand.index, val->node); |  | 
| 1158           p->tree->node = val->node; |  | 
| 1159         } else { |  | 
| 1160           error(p->pc(), val->pc, "Typecheck failed in StoreGlobal"); |  | 
| 1161         } |  | 
| 1162         break; |  | 
| 1163       } |  | 
| 1164 |  | 
| 1165       case kExprI32LoadMem8S: |  | 
| 1166         return ReduceLoadMem(p, kAstI32, MachineType::Int8()); |  | 
| 1167       case kExprI32LoadMem8U: |  | 
| 1168         return ReduceLoadMem(p, kAstI32, MachineType::Uint8()); |  | 
| 1169       case kExprI32LoadMem16S: |  | 
| 1170         return ReduceLoadMem(p, kAstI32, MachineType::Int16()); |  | 
| 1171       case kExprI32LoadMem16U: |  | 
| 1172         return ReduceLoadMem(p, kAstI32, MachineType::Uint16()); |  | 
| 1173       case kExprI32LoadMem: |  | 
| 1174         return ReduceLoadMem(p, kAstI32, MachineType::Int32()); |  | 
| 1175 |  | 
| 1176       case kExprI64LoadMem8S: |  | 
| 1177         return ReduceLoadMem(p, kAstI64, MachineType::Int8()); |  | 
| 1178       case kExprI64LoadMem8U: |  | 
| 1179         return ReduceLoadMem(p, kAstI64, MachineType::Uint8()); |  | 
| 1180       case kExprI64LoadMem16S: |  | 
| 1181         return ReduceLoadMem(p, kAstI64, MachineType::Int16()); |  | 
| 1182       case kExprI64LoadMem16U: |  | 
| 1183         return ReduceLoadMem(p, kAstI64, MachineType::Uint16()); |  | 
| 1184       case kExprI64LoadMem32S: |  | 
| 1185         return ReduceLoadMem(p, kAstI64, MachineType::Int32()); |  | 
| 1186       case kExprI64LoadMem32U: |  | 
| 1187         return ReduceLoadMem(p, kAstI64, MachineType::Uint32()); |  | 
| 1188       case kExprI64LoadMem: |  | 
| 1189         return ReduceLoadMem(p, kAstI64, MachineType::Int64()); |  | 
| 1190 |  | 
| 1191       case kExprF32LoadMem: |  | 
| 1192         return ReduceLoadMem(p, kAstF32, MachineType::Float32()); |  | 
| 1193 |  | 
| 1194       case kExprF64LoadMem: |  | 
| 1195         return ReduceLoadMem(p, kAstF64, MachineType::Float64()); |  | 
| 1196 |  | 
| 1197       case kExprI32StoreMem8: |  | 
| 1198         return ReduceStoreMem(p, kAstI32, MachineType::Int8()); |  | 
| 1199       case kExprI32StoreMem16: |  | 
| 1200         return ReduceStoreMem(p, kAstI32, MachineType::Int16()); |  | 
| 1201       case kExprI32StoreMem: |  | 
| 1202         return ReduceStoreMem(p, kAstI32, MachineType::Int32()); |  | 
| 1203 |  | 
| 1204       case kExprI64StoreMem8: |  | 
| 1205         return ReduceStoreMem(p, kAstI64, MachineType::Int8()); |  | 
| 1206       case kExprI64StoreMem16: |  | 
| 1207         return ReduceStoreMem(p, kAstI64, MachineType::Int16()); |  | 
| 1208       case kExprI64StoreMem32: |  | 
| 1209         return ReduceStoreMem(p, kAstI64, MachineType::Int32()); |  | 
| 1210       case kExprI64StoreMem: |  | 
| 1211         return ReduceStoreMem(p, kAstI64, MachineType::Int64()); |  | 
| 1212 |  | 
| 1213       case kExprF32StoreMem: |  | 
| 1214         return ReduceStoreMem(p, kAstF32, MachineType::Float32()); |  | 
| 1215 |  | 
| 1216       case kExprF64StoreMem: |  | 
| 1217         return ReduceStoreMem(p, kAstF64, MachineType::Float64()); |  | 
| 1218 |  | 
| 1219       case kExprGrowMemory: |  | 
| 1220         TypeCheckLast(p, kAstI32); |  | 
| 1221         // TODO(titzer): build node for GrowMemory |  | 
| 1222         p->tree->node = BUILD(Int32Constant, 0); |  | 
| 1223         return; |  | 
| 1224 |  | 
| 1225       case kExprCallFunction: { |  | 
| 1226         FunctionIndexOperand operand(this, p->pc()); |  | 
| 1227         CHECK(Validate(p->pc(), operand)); |  | 
| 1228         if (p->index > 0) { |  | 
| 1229           TypeCheckLast(p, operand.sig->GetParam(p->index - 1)); |  | 
| 1230         } |  | 
| 1231         if (p->done() && build()) { |  | 
| 1232           uint32_t count = p->tree->count + 1; |  | 
| 1233           TFNode** buffer = builder_->Buffer(count); |  | 
| 1234           buffer[0] = nullptr;  // reserved for code object. |  | 
| 1235           for (uint32_t i = 1; i < count; i++) { |  | 
| 1236             buffer[i] = p->tree->children[i - 1]->node; |  | 
| 1237           } |  | 
| 1238           p->tree->node = builder_->CallDirect(operand.index, buffer); |  | 
| 1239           AddSourcePosition(p); |  | 
| 1240         } |  | 
| 1241         break; |  | 
| 1242       } |  | 
| 1243       case kExprCallIndirect: { |  | 
| 1244         SignatureIndexOperand operand(this, p->pc()); |  | 
| 1245         CHECK(Validate(p->pc(), operand)); |  | 
| 1246         if (p->index == 1) { |  | 
| 1247           TypeCheckLast(p, kAstI32); |  | 
| 1248         } else { |  | 
| 1249           TypeCheckLast(p, operand.sig->GetParam(p->index - 2)); |  | 
| 1250         } |  | 
| 1251         if (p->done() && build()) { |  | 
| 1252           uint32_t count = p->tree->count; |  | 
| 1253           TFNode** buffer = builder_->Buffer(count); |  | 
| 1254           for (uint32_t i = 0; i < count; i++) { |  | 
| 1255             buffer[i] = p->tree->children[i]->node; |  | 
| 1256           } |  | 
| 1257           p->tree->node = builder_->CallIndirect(operand.index, buffer); |  | 
| 1258           AddSourcePosition(p); |  | 
| 1259         } |  | 
| 1260         break; |  | 
| 1261       } |  | 
| 1262       case kExprCallImport: { |  | 
| 1263         ImportIndexOperand operand(this, p->pc()); |  | 
| 1264         CHECK(Validate(p->pc(), operand)); |  | 
| 1265         if (p->index > 0) { |  | 
| 1266           TypeCheckLast(p, operand.sig->GetParam(p->index - 1)); |  | 
| 1267         } |  | 
| 1268         if (p->done() && build()) { |  | 
| 1269           uint32_t count = p->tree->count + 1; |  | 
| 1270           TFNode** buffer = builder_->Buffer(count); |  | 
| 1271           buffer[0] = nullptr;  // reserved for code object. |  | 
| 1272           for (uint32_t i = 1; i < count; i++) { |  | 
| 1273             buffer[i] = p->tree->children[i - 1]->node; |  | 
| 1274           } |  | 
| 1275           p->tree->node = builder_->CallImport(operand.index, buffer); |  | 
| 1276           AddSourcePosition(p); |  | 
| 1277         } |  | 
| 1278         break; |  | 
| 1279       } |  | 
| 1280       default: |  | 
| 1281         break; |  | 
| 1282     } |  | 
| 1283   } |  | 
| 1284 |  | 
| 1285   void ReduceBreakToExprBlock(Production* p, Block* block) { |  | 
| 1286     ReduceBreakToExprBlock(p, block, p->tree->count > 0 ? p->last() : nullptr); |  | 
| 1287   } |  | 
| 1288 |  | 
| 1289   void ReduceBreakToExprBlock(Production* p, Block* block, Tree* val) { |  | 
| 1290     if (block->stack_depth < 0) { |  | 
| 1291       // This is the inner loop block, which does not have a value. |  | 
| 1292       Goto(ssa_env_, block->ssa_env); |  | 
| 1293     } else { |  | 
| 1294       // Merge the value into the production for the block. |  | 
| 1295       Production* bp = &stack_[block->stack_depth]; |  | 
| 1296       MergeIntoProduction(bp, block->ssa_env, val); |  | 
| 1297     } |  | 
| 1298   } |  | 
| 1299 |  | 
| 1300   void MergeIntoProduction(Production* p, SsaEnv* target, Tree* expr) { |  | 
| 1301     if (!ssa_env_->go()) return; |  | 
| 1302 |  | 
| 1303     bool first = target->state == SsaEnv::kUnreachable; |  | 
| 1304     Goto(ssa_env_, target); |  | 
| 1305     if (expr == nullptr || expr->type == kAstEnd) return; |  | 
| 1306 |  | 
| 1307     if (first) { |  | 
| 1308       // first merge to this environment; set the type and the node. |  | 
| 1309       p->tree->type = expr->type; |  | 
| 1310       p->tree->node = expr->node; |  | 
| 1311     } else { |  | 
| 1312       // merge with the existing value for this block. |  | 
| 1313       LocalType type = p->tree->type; |  | 
| 1314       if (expr->type != type) { |  | 
| 1315         type = kAstStmt; |  | 
| 1316         p->tree->type = kAstStmt; |  | 
| 1317         p->tree->node = nullptr; |  | 
| 1318       } else if (type != kAstStmt) { |  | 
| 1319         p->tree->node = CreateOrMergeIntoPhi(type, target->control, |  | 
| 1320                                              p->tree->node, expr->node); |  | 
| 1321       } |  | 
| 1322     } |  | 
| 1323   } |  | 
| 1324 |  | 
| 1325   void ReduceLoadMem(Production* p, LocalType type, MachineType mem_type) { |  | 
| 1326     DCHECK_EQ(1, p->index); |  | 
| 1327     TypeCheckLast(p, kAstI32);  // index |  | 
| 1328     if (build()) { |  | 
| 1329       MemoryAccessOperand operand(this, p->pc()); |  | 
| 1330       p->tree->node = |  | 
| 1331           builder_->LoadMem(type, mem_type, p->last()->node, operand.offset); |  | 
| 1332     } |  | 
| 1333   } |  | 
| 1334 |  | 
| 1335   void ReduceStoreMem(Production* p, LocalType type, MachineType mem_type) { |  | 
| 1336     if (p->index == 1) { |  | 
| 1337       TypeCheckLast(p, kAstI32);  // index |  | 
| 1338     } else { |  | 
| 1339       DCHECK_EQ(2, p->index); |  | 
| 1340       TypeCheckLast(p, type); |  | 
| 1341       if (build()) { |  | 
| 1342         MemoryAccessOperand operand(this, p->pc()); |  | 
| 1343         TFNode* val = p->tree->children[1]->node; |  | 
| 1344         builder_->StoreMem(mem_type, p->tree->children[0]->node, operand.offset, |  | 
| 1345                            val); |  | 
| 1346         p->tree->node = val; |  | 
| 1347       } |  | 
| 1348     } |  | 
| 1349   } |  | 
| 1350 |  | 
| 1351   void TypeCheckLast(Production* p, LocalType expected) { |  | 
| 1352     LocalType result = p->last()->type; |  | 
| 1353     if (result == expected) return; |  | 
| 1354     if (result == kAstEnd) return; |  | 
| 1355     if (expected != kAstStmt) { |  | 
| 1356       error(p->pc(), p->last()->pc, |  | 
| 1357             "%s[%d] expected type %s, found %s of type %s", |  | 
| 1358             WasmOpcodes::OpcodeName(p->opcode()), p->index - 1, |  | 
| 1359             WasmOpcodes::TypeName(expected), |  | 
| 1360             WasmOpcodes::OpcodeName(p->last()->opcode()), |  | 
| 1361             WasmOpcodes::TypeName(p->last()->type)); |  | 
| 1362     } |  | 
| 1363   } |  | 
| 1364 |  | 
| 1365   void SetEnv(const char* reason, SsaEnv* env) { |  | 
| 1366 #if DEBUG |  | 
| 1367     TRACE("  env = %p, block depth = %d, reason = %s", static_cast<void*>(env), |  | 
| 1368           static_cast<int>(blocks_.size()), reason); |  | 
| 1369     if (FLAG_trace_wasm_decoder && env && env->control) { |  | 
| 1370       TRACE(", control = "); |  | 
| 1371       compiler::WasmGraphBuilder::PrintDebugName(env->control); |  | 
| 1372     } |  | 
| 1373     TRACE("\n"); |  | 
| 1374 #endif | 1249 #endif | 
| 1375     ssa_env_ = env; | 1250     ssa_env_ = env; | 
| 1376     if (builder_) { | 1251     if (builder_) { | 
| 1377       builder_->set_control_ptr(&env->control); | 1252       builder_->set_control_ptr(&env->control); | 
| 1378       builder_->set_effect_ptr(&env->effect); | 1253       builder_->set_effect_ptr(&env->effect); | 
| 1379     } | 1254     } | 
| 1380   } | 1255   } | 
| 1381 | 1256 | 
| 1382   void Goto(SsaEnv* from, SsaEnv* to) { | 1257   void Goto(SsaEnv* from, SsaEnv* to) { | 
| 1383     DCHECK_NOT_NULL(to); | 1258     DCHECK_NOT_NULL(to); | 
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 1497     } | 1372     } | 
| 1498   } | 1373   } | 
| 1499 | 1374 | 
| 1500   // Create a complete copy of the {from}. | 1375   // Create a complete copy of the {from}. | 
| 1501   SsaEnv* Split(SsaEnv* from) { | 1376   SsaEnv* Split(SsaEnv* from) { | 
| 1502     DCHECK_NOT_NULL(from); | 1377     DCHECK_NOT_NULL(from); | 
| 1503     SsaEnv* result = reinterpret_cast<SsaEnv*>(zone_->New(sizeof(SsaEnv))); | 1378     SsaEnv* result = reinterpret_cast<SsaEnv*>(zone_->New(sizeof(SsaEnv))); | 
| 1504     size_t size = sizeof(TFNode*) * EnvironmentCount(); | 1379     size_t size = sizeof(TFNode*) * EnvironmentCount(); | 
| 1505     result->control = from->control; | 1380     result->control = from->control; | 
| 1506     result->effect = from->effect; | 1381     result->effect = from->effect; | 
| 1507     result->state = from->state == SsaEnv::kUnreachable ? SsaEnv::kUnreachable |  | 
| 1508                                                         : SsaEnv::kReached; |  | 
| 1509 | 1382 | 
| 1510     if (from->go()) { | 1383     if (from->go()) { | 
| 1511       result->state = SsaEnv::kReached; | 1384       result->state = SsaEnv::kReached; | 
| 1512       result->locals = | 1385       result->locals = | 
| 1513           size > 0 ? reinterpret_cast<TFNode**>(zone_->New(size)) : nullptr; | 1386           size > 0 ? reinterpret_cast<TFNode**>(zone_->New(size)) : nullptr; | 
| 1514       memcpy(result->locals, from->locals, size); | 1387       memcpy(result->locals, from->locals, size); | 
| 1515     } else { | 1388     } else { | 
| 1516       result->state = SsaEnv::kUnreachable; | 1389       result->state = SsaEnv::kUnreachable; | 
| 1517       result->locals = nullptr; | 1390       result->locals = nullptr; | 
| 1518     } | 1391     } | 
| (...skipping 26 matching lines...) Expand all  Loading... | 
| 1545   } | 1418   } | 
| 1546 | 1419 | 
| 1547   int EnvironmentCount() { | 1420   int EnvironmentCount() { | 
| 1548     if (builder_) return static_cast<int>(local_type_vec_.size()); | 1421     if (builder_) return static_cast<int>(local_type_vec_.size()); | 
| 1549     return 0;  // if we aren't building a graph, don't bother with SSA renaming. | 1422     return 0;  // if we aren't building a graph, don't bother with SSA renaming. | 
| 1550   } | 1423   } | 
| 1551 | 1424 | 
| 1552   virtual void onFirstError() { | 1425   virtual void onFirstError() { | 
| 1553     limit_ = start_;     // Terminate decoding loop. | 1426     limit_ = start_;     // Terminate decoding loop. | 
| 1554     builder_ = nullptr;  // Don't build any more nodes. | 1427     builder_ = nullptr;  // Don't build any more nodes. | 
| 1555 #if DEBUG | 1428     TRACE(" !%s\n", error_msg_.get()); | 
| 1556     PrintStackForDebugging(); |  | 
| 1557 #endif |  | 
| 1558   } | 1429   } | 
| 1559 |  | 
| 1560 #if DEBUG |  | 
| 1561   void PrintStackForDebugging() { PrintProduction(0); } |  | 
| 1562 |  | 
| 1563   void PrintProduction(size_t depth) { |  | 
| 1564     if (depth >= stack_.size()) return; |  | 
| 1565     Production* p = &stack_[depth]; |  | 
| 1566     for (size_t d = 0; d < depth; d++) PrintF("  "); |  | 
| 1567 |  | 
| 1568     PrintF("@%d %s [%d]\n", static_cast<int>(p->tree->pc - start_), |  | 
| 1569            WasmOpcodes::OpcodeName(p->opcode()), p->tree->count); |  | 
| 1570     for (int i = 0; i < p->index; i++) { |  | 
| 1571       Tree* child = p->tree->children[i]; |  | 
| 1572       for (size_t d = 0; d <= depth; d++) PrintF("  "); |  | 
| 1573       PrintF("@%d %s [%d]", static_cast<int>(child->pc - start_), |  | 
| 1574              WasmOpcodes::OpcodeName(child->opcode()), child->count); |  | 
| 1575       if (child->node) { |  | 
| 1576         PrintF(" => TF"); |  | 
| 1577         compiler::WasmGraphBuilder::PrintDebugName(child->node); |  | 
| 1578       } |  | 
| 1579       PrintF("\n"); |  | 
| 1580     } |  | 
| 1581     PrintProduction(depth + 1); |  | 
| 1582   } |  | 
| 1583 #endif |  | 
| 1584 |  | 
| 1585   BitVector* AnalyzeLoopAssignment(const byte* pc) { | 1430   BitVector* AnalyzeLoopAssignment(const byte* pc) { | 
| 1586     if (pc >= limit_) return nullptr; | 1431     if (pc >= limit_) return nullptr; | 
| 1587     if (*pc != kExprLoop) return nullptr; | 1432     if (*pc != kExprLoop) return nullptr; | 
| 1588 | 1433 | 
| 1589     BitVector* assigned = | 1434     BitVector* assigned = | 
| 1590         new (zone_) BitVector(static_cast<int>(total_locals_), zone_); | 1435         new (zone_) BitVector(static_cast<int>(local_type_vec_.size()), zone_); | 
| 1591     // Keep a stack to model the nesting of expressions. | 1436     int depth = 0; | 
| 1592     std::vector<int> arity_stack; |  | 
| 1593     arity_stack.push_back(OpcodeArity(pc)); |  | 
| 1594     pc += OpcodeLength(pc); |  | 
| 1595 |  | 
| 1596     // Iteratively process all AST nodes nested inside the loop. | 1437     // Iteratively process all AST nodes nested inside the loop. | 
| 1597     while (pc < limit_) { | 1438     while (pc < limit_) { | 
| 1598       WasmOpcode opcode = static_cast<WasmOpcode>(*pc); | 1439       WasmOpcode opcode = static_cast<WasmOpcode>(*pc); | 
| 1599       int arity = 0; |  | 
| 1600       int length = 1; | 1440       int length = 1; | 
| 1601       int assigned_index = -1; | 1441       switch (opcode) { | 
| 1602       if (opcode == kExprSetLocal) { | 1442         case kExprLoop: | 
| 1603         LocalIndexOperand operand(this, pc); | 1443         case kExprIf: | 
| 1604         if (assigned->length() > 0 && | 1444         case kExprBlock: | 
| 1605             static_cast<int>(operand.index) < assigned->length()) { | 1445           depth++; | 
| 1606           // Unverified code might have an out-of-bounds index. | 1446           DCHECK_EQ(1, OpcodeLength(pc)); | 
| 1607           // Ignore out-of-bounds indices, as the main verification will fail. | 1447           break; | 
| 1608           assigned->Add(operand.index); | 1448         case kExprSetLocal: { | 
| 1609           assigned_index = operand.index; | 1449           LocalIndexOperand operand(this, pc); | 
|  | 1450           if (assigned->length() > 0 && | 
|  | 1451               static_cast<int>(operand.index) < assigned->length()) { | 
|  | 1452             // Unverified code might have an out-of-bounds index. | 
|  | 1453             assigned->Add(operand.index); | 
|  | 1454           } | 
|  | 1455           length = 1 + operand.length; | 
|  | 1456           break; | 
| 1610         } | 1457         } | 
| 1611         arity = 1; | 1458         case kExprEnd: | 
| 1612         length = 1 + operand.length; | 1459           depth--; | 
| 1613       } else { | 1460           break; | 
| 1614         arity = OpcodeArity(pc); | 1461         default: | 
| 1615         length = OpcodeLength(pc); | 1462           length = OpcodeLength(pc); | 
|  | 1463           break; | 
| 1616       } | 1464       } | 
| 1617 | 1465       if (depth <= 0) break; | 
| 1618       TRACE("loop-assign module+%-6d %s func+%d: 0x%02x %s", baserel(pc), |  | 
| 1619             indentation(), startrel(pc), opcode, |  | 
| 1620             WasmOpcodes::OpcodeName(opcode)); |  | 
| 1621 |  | 
| 1622       if (assigned_index >= 0) { |  | 
| 1623         TRACE(" (assigned local #%d)\n", assigned_index); |  | 
| 1624       } else { |  | 
| 1625         TRACE("\n"); |  | 
| 1626       } |  | 
| 1627 |  | 
| 1628       pc += length; | 1466       pc += length; | 
| 1629       arity_stack.push_back(arity); |  | 
| 1630       while (arity_stack.back() == 0) { |  | 
| 1631         arity_stack.pop_back(); |  | 
| 1632         if (arity_stack.empty()) return assigned;  // reached end of loop |  | 
| 1633         arity_stack.back()--; |  | 
| 1634       } |  | 
| 1635     } | 1467     } | 
| 1636     return assigned; | 1468     return assigned; | 
| 1637   } | 1469   } | 
| 1638 | 1470 | 
| 1639   void AddSourcePosition(Production* p) { |  | 
| 1640     DCHECK_NOT_NULL(p->tree->node); |  | 
| 1641     AddSourcePosition(p->tree->node, p->pc()); |  | 
| 1642   } |  | 
| 1643 |  | 
| 1644   void AddSourcePosition(TFNode* node, const byte* pc) { | 1471   void AddSourcePosition(TFNode* node, const byte* pc) { | 
| 1645     int offset = static_cast<int>(pc - start_); | 1472     if (node) { | 
| 1646     DCHECK_EQ(pc - start_, offset);  // overflows cannot happen | 1473       int offset = static_cast<int>(pc - start_); | 
| 1647     builder_->SetSourcePosition(node, offset); | 1474       DCHECK_EQ(pc - start_, offset);  // overflows cannot happen | 
|  | 1475       builder_->SetSourcePosition(node, offset); | 
|  | 1476     } | 
| 1648   } | 1477   } | 
| 1649 }; | 1478 }; | 
| 1650 | 1479 | 
| 1651 bool DecodeLocalDecls(AstLocalDecls& decls, const byte* start, | 1480 bool DecodeLocalDecls(AstLocalDecls& decls, const byte* start, | 
| 1652                       const byte* end) { | 1481                       const byte* end) { | 
| 1653   base::AccountingAllocator allocator; | 1482   base::AccountingAllocator allocator; | 
| 1654   Zone tmp(&allocator); | 1483   Zone tmp(&allocator); | 
| 1655   FunctionBody body = {nullptr, nullptr, nullptr, start, end}; | 1484   FunctionBody body = {nullptr, nullptr, nullptr, start, end}; | 
| 1656   SR_WasmDecoder decoder(&tmp, nullptr, body); | 1485   SR_WasmDecoder decoder(&tmp, nullptr, body); | 
| 1657   return decoder.DecodeLocalDecls(decls); | 1486   return decoder.DecodeLocalDecls(decls); | 
| 1658 } | 1487 } | 
| 1659 | 1488 | 
| 1660 TreeResult VerifyWasmCode(base::AccountingAllocator* allocator, | 1489 TreeResult VerifyWasmCode(base::AccountingAllocator* allocator, | 
| 1661                           FunctionBody& body) { | 1490                           FunctionBody& body) { | 
| 1662   Zone zone(allocator); | 1491   Zone zone(allocator); | 
| 1663   SR_WasmDecoder decoder(&zone, nullptr, body); | 1492   SR_WasmDecoder decoder(&zone, nullptr, body); | 
| 1664   TreeResult result = decoder.Decode(); | 1493   decoder.Decode(); | 
| 1665   return result; | 1494   return decoder.toResult<Tree*>(nullptr); | 
| 1666 } | 1495 } | 
| 1667 | 1496 | 
| 1668 TreeResult BuildTFGraph(base::AccountingAllocator* allocator, | 1497 TreeResult BuildTFGraph(base::AccountingAllocator* allocator, | 
| 1669                         TFBuilder* builder, FunctionBody& body) { | 1498                         TFBuilder* builder, FunctionBody& body) { | 
| 1670   Zone zone(allocator); | 1499   Zone zone(allocator); | 
| 1671   SR_WasmDecoder decoder(&zone, builder, body); | 1500   SR_WasmDecoder decoder(&zone, builder, body); | 
| 1672   TreeResult result = decoder.Decode(); | 1501   decoder.Decode(); | 
| 1673   return result; | 1502   return decoder.toResult<Tree*>(nullptr); | 
| 1674 } | 1503 } | 
| 1675 | 1504 | 
| 1676 | 1505 | 
| 1677 std::ostream& operator<<(std::ostream& os, const Tree& tree) { | 1506 std::ostream& operator<<(std::ostream& os, const Tree& tree) { | 
| 1678   if (tree.pc == nullptr) { | 1507   if (tree.pc == nullptr) { | 
| 1679     os << "null"; | 1508     os << "null"; | 
| 1680     return os; | 1509     return os; | 
| 1681   } | 1510   } | 
| 1682   PrintF("%s", WasmOpcodes::OpcodeName(tree.opcode())); | 1511   PrintF("%s", WasmOpcodes::OpcodeName(tree.opcode())); | 
| 1683   if (tree.count > 0) os << "("; | 1512   if (tree.count > 0) os << "("; | 
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 1744     WasmOpcode opcode = static_cast<WasmOpcode>(*pc); | 1573     WasmOpcode opcode = static_cast<WasmOpcode>(*pc); | 
| 1745     printf("k%s,", WasmOpcodes::OpcodeName(opcode)); | 1574     printf("k%s,", WasmOpcodes::OpcodeName(opcode)); | 
| 1746 | 1575 | 
| 1747     for (size_t i = 1; i < length; i++) { | 1576     for (size_t i = 1; i < length; i++) { | 
| 1748       printf(" 0x%02x,", pc[i]); | 1577       printf(" 0x%02x,", pc[i]); | 
| 1749     } | 1578     } | 
| 1750 | 1579 | 
| 1751     if (body.module) { | 1580     if (body.module) { | 
| 1752       switch (opcode) { | 1581       switch (opcode) { | 
| 1753         case kExprCallIndirect: { | 1582         case kExprCallIndirect: { | 
| 1754           SignatureIndexOperand operand(&decoder, pc); | 1583           CallIndirectOperand operand(&decoder, pc); | 
| 1755           if (decoder.Validate(pc, operand)) { | 1584           if (decoder.Validate(pc, operand)) { | 
| 1756             os << " // sig #" << operand.index << ": " << *operand.sig; | 1585             os << " // sig #" << operand.index << ": " << *operand.sig; | 
| 1757           } | 1586           } | 
| 1758           break; | 1587           break; | 
| 1759         } | 1588         } | 
| 1760         case kExprCallImport: { | 1589         case kExprCallImport: { | 
| 1761           ImportIndexOperand operand(&decoder, pc); | 1590           CallImportOperand operand(&decoder, pc); | 
| 1762           if (decoder.Validate(pc, operand)) { | 1591           if (decoder.Validate(pc, operand)) { | 
| 1763             os << " // import #" << operand.index << ": " << *operand.sig; | 1592             os << " // import #" << operand.index << ": " << *operand.sig; | 
| 1764           } | 1593           } | 
| 1765           break; | 1594           break; | 
| 1766         } | 1595         } | 
| 1767         case kExprCallFunction: { | 1596         case kExprCallFunction: { | 
| 1768           FunctionIndexOperand operand(&decoder, pc); | 1597           CallFunctionOperand operand(&decoder, pc); | 
| 1769           if (decoder.Validate(pc, operand)) { | 1598           if (decoder.Validate(pc, operand)) { | 
| 1770             os << " // function #" << operand.index << ": " << *operand.sig; | 1599             os << " // function #" << operand.index << ": " << *operand.sig; | 
| 1771           } | 1600           } | 
| 1772           break; | 1601           break; | 
| 1773         } | 1602         } | 
| 1774         default: | 1603         default: | 
| 1775           break; | 1604           break; | 
| 1776       } | 1605       } | 
| 1777     } | 1606     } | 
| 1778 | 1607 | 
| (...skipping 12 matching lines...) Expand all  Loading... | 
| 1791 BitVector* AnalyzeLoopAssignmentForTesting(Zone* zone, size_t num_locals, | 1620 BitVector* AnalyzeLoopAssignmentForTesting(Zone* zone, size_t num_locals, | 
| 1792                                            const byte* start, const byte* end) { | 1621                                            const byte* start, const byte* end) { | 
| 1793   FunctionBody body = {nullptr, nullptr, nullptr, start, end}; | 1622   FunctionBody body = {nullptr, nullptr, nullptr, start, end}; | 
| 1794   SR_WasmDecoder decoder(zone, nullptr, body); | 1623   SR_WasmDecoder decoder(zone, nullptr, body); | 
| 1795   return decoder.AnalyzeLoopAssignmentForTesting(start, num_locals); | 1624   return decoder.AnalyzeLoopAssignmentForTesting(start, num_locals); | 
| 1796 } | 1625 } | 
| 1797 | 1626 | 
| 1798 }  // namespace wasm | 1627 }  // namespace wasm | 
| 1799 }  // namespace internal | 1628 }  // namespace internal | 
| 1800 }  // namespace v8 | 1629 }  // namespace v8 | 
| OLD | NEW | 
|---|