OLD | NEW |
1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/base/platform/elapsed-timer.h" | 5 #include "src/base/platform/elapsed-timer.h" |
6 #include "src/signature.h" | 6 #include "src/signature.h" |
7 | 7 |
| 8 #include "src/bit-vector.h" |
8 #include "src/flags.h" | 9 #include "src/flags.h" |
9 #include "src/handles.h" | 10 #include "src/handles.h" |
10 #include "src/zone-containers.h" | 11 #include "src/zone-containers.h" |
11 | 12 |
12 #include "src/wasm/ast-decoder.h" | 13 #include "src/wasm/ast-decoder.h" |
13 #include "src/wasm/decoder.h" | 14 #include "src/wasm/decoder.h" |
14 #include "src/wasm/wasm-module.h" | 15 #include "src/wasm/wasm-module.h" |
15 #include "src/wasm/wasm-opcodes.h" | 16 #include "src/wasm/wasm-opcodes.h" |
16 | 17 |
17 #include "src/compiler/wasm-compiler.h" | 18 #include "src/compiler/wasm-compiler.h" |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
90 }; | 91 }; |
91 | 92 |
92 | 93 |
93 // Macros that build nodes only if there is a graph and the current SSA | 94 // Macros that build nodes only if there is a graph and the current SSA |
94 // environment is reachable from start. This avoids problems with malformed | 95 // environment is reachable from start. This avoids problems with malformed |
95 // TF graphs when decoding inputs that have unreachable code. | 96 // TF graphs when decoding inputs that have unreachable code. |
96 #define BUILD(func, ...) (build() ? builder_->func(__VA_ARGS__) : nullptr) | 97 #define BUILD(func, ...) (build() ? builder_->func(__VA_ARGS__) : nullptr) |
97 #define BUILD0(func) (build() ? builder_->func() : nullptr) | 98 #define BUILD0(func) (build() ? builder_->func() : nullptr) |
98 | 99 |
99 | 100 |
| 101 // Generic Wasm bytecode decoder with utilities for decoding operands, |
| 102 // lengths, etc. |
| 103 class WasmDecoder : public Decoder { |
| 104 public: |
| 105 WasmDecoder() : Decoder(nullptr, nullptr), function_env_(nullptr) {} |
| 106 |
| 107 protected: |
| 108 FunctionEnv* function_env_; |
| 109 |
| 110 void Reset(FunctionEnv* function_env, const byte* start, const byte* end) { |
| 111 Decoder::Reset(start, end); |
| 112 function_env_ = function_env; |
| 113 } |
| 114 |
| 115 // Load an operand at [pc + 1]. |
| 116 template <typename V> |
| 117 V Operand(const byte* pc) { |
| 118 if ((limit_ - pc) < static_cast<int>(1 + sizeof(V))) { |
| 119 const char* msg = "Expected operand following opcode"; |
| 120 switch (sizeof(V)) { |
| 121 case 1: |
| 122 msg = "Expected 1-byte operand following opcode"; |
| 123 break; |
| 124 case 2: |
| 125 msg = "Expected 2-byte operand following opcode"; |
| 126 break; |
| 127 case 4: |
| 128 msg = "Expected 4-byte operand following opcode"; |
| 129 break; |
| 130 default: |
| 131 break; |
| 132 } |
| 133 error(pc, msg); |
| 134 return -1; |
| 135 } |
| 136 return *reinterpret_cast<const V*>(pc + 1); |
| 137 } |
| 138 |
| 139 LocalType LocalOperand(const byte* pc, uint32_t* index, int* length) { |
| 140 *index = UnsignedLEB128Operand(pc, length); |
| 141 if (function_env_->IsValidLocal(*index)) { |
| 142 return function_env_->GetLocalType(*index); |
| 143 } |
| 144 error(pc, "invalid local variable index"); |
| 145 return kAstStmt; |
| 146 } |
| 147 |
| 148 LocalType GlobalOperand(const byte* pc, uint32_t* index, int* length) { |
| 149 *index = UnsignedLEB128Operand(pc, length); |
| 150 if (function_env_->module->IsValidGlobal(*index)) { |
| 151 return WasmOpcodes::LocalTypeFor( |
| 152 function_env_->module->GetGlobalType(*index)); |
| 153 } |
| 154 error(pc, "invalid global variable index"); |
| 155 return kAstStmt; |
| 156 } |
| 157 |
| 158 FunctionSig* FunctionSigOperand(const byte* pc, uint32_t* index, |
| 159 int* length) { |
| 160 *index = UnsignedLEB128Operand(pc, length); |
| 161 if (function_env_->module->IsValidFunction(*index)) { |
| 162 return function_env_->module->GetFunctionSignature(*index); |
| 163 } |
| 164 error(pc, "invalid function index"); |
| 165 return nullptr; |
| 166 } |
| 167 |
| 168 FunctionSig* SigOperand(const byte* pc, uint32_t* index, int* length) { |
| 169 *index = UnsignedLEB128Operand(pc, length); |
| 170 if (function_env_->module->IsValidSignature(*index)) { |
| 171 return function_env_->module->GetSignature(*index); |
| 172 } |
| 173 error(pc, "invalid signature index"); |
| 174 return nullptr; |
| 175 } |
| 176 |
| 177 uint32_t UnsignedLEB128Operand(const byte* pc, int* length) { |
| 178 uint32_t result = 0; |
| 179 ReadUnsignedLEB128ErrorCode error_code = |
| 180 ReadUnsignedLEB128Operand(pc + 1, limit_, length, &result); |
| 181 if (error_code == kInvalidLEB128) error(pc, "invalid LEB128 varint"); |
| 182 if (error_code == kMissingLEB128) error(pc, "expected LEB128 varint"); |
| 183 (*length)++; |
| 184 return result; |
| 185 } |
| 186 |
| 187 void MemoryAccessOperand(const byte* pc, int* length, uint32_t* offset) { |
| 188 byte bitfield = Operand<uint8_t>(pc); |
| 189 if (MemoryAccess::OffsetField::decode(bitfield)) { |
| 190 *offset = UnsignedLEB128Operand(pc + 1, length); |
| 191 (*length)++; // to account for the memory access byte |
| 192 } else { |
| 193 *offset = 0; |
| 194 *length = 2; |
| 195 } |
| 196 } |
| 197 }; |
| 198 |
| 199 |
100 // A shift-reduce-parser strategy for decoding Wasm code that uses an explicit | 200 // A shift-reduce-parser strategy for decoding Wasm code that uses an explicit |
101 // shift-reduce strategy with multiple internal stacks. | 201 // shift-reduce strategy with multiple internal stacks. |
102 class LR_WasmDecoder : public Decoder { | 202 class LR_WasmDecoder : public WasmDecoder { |
103 public: | 203 public: |
104 LR_WasmDecoder(Zone* zone, TFBuilder* builder) | 204 LR_WasmDecoder(Zone* zone, TFBuilder* builder) |
105 : Decoder(nullptr, nullptr), | 205 : zone_(zone), |
106 zone_(zone), | |
107 builder_(builder), | 206 builder_(builder), |
108 trees_(zone), | 207 trees_(zone), |
109 stack_(zone), | 208 stack_(zone), |
110 blocks_(zone), | 209 blocks_(zone), |
111 ifs_(zone) {} | 210 ifs_(zone) {} |
112 | 211 |
113 TreeResult Decode(FunctionEnv* function_env, const byte* base, const byte* pc, | 212 TreeResult Decode(FunctionEnv* function_env, const byte* base, const byte* pc, |
114 const byte* end) { | 213 const byte* end) { |
115 base::ElapsedTimer decode_timer; | 214 base::ElapsedTimer decode_timer; |
116 if (FLAG_trace_wasm_decode_time) { | 215 if (FLAG_trace_wasm_decode_time) { |
117 decode_timer.Start(); | 216 decode_timer.Start(); |
118 } | 217 } |
119 trees_.clear(); | 218 trees_.clear(); |
120 stack_.clear(); | 219 stack_.clear(); |
121 blocks_.clear(); | 220 blocks_.clear(); |
122 ifs_.clear(); | 221 ifs_.clear(); |
123 | 222 |
124 if (end < pc) { | 223 if (end < pc) { |
125 error(pc, "function body end < start"); | 224 error(pc, "function body end < start"); |
126 return result_; | 225 return result_; |
127 } | 226 } |
128 | 227 |
129 base_ = base; | 228 base_ = base; |
130 Reset(pc, end); | 229 Reset(function_env, pc, end); |
131 function_env_ = function_env; | |
132 | 230 |
133 InitSsaEnv(); | 231 InitSsaEnv(); |
134 DecodeFunctionBody(); | 232 DecodeFunctionBody(); |
135 | 233 |
136 Tree* tree = nullptr; | 234 Tree* tree = nullptr; |
137 if (ok()) { | 235 if (ok()) { |
138 if (ssa_env_->go()) { | 236 if (ssa_env_->go()) { |
139 if (stack_.size() > 0) { | 237 if (stack_.size() > 0) { |
140 error(stack_.back().pc(), end, "fell off end of code"); | 238 error(stack_.back().pc(), end, "fell off end of code"); |
141 } | 239 } |
(...skipping 28 matching lines...) Expand all Loading... |
170 | 268 |
171 private: | 269 private: |
172 static const size_t kErrorMsgSize = 128; | 270 static const size_t kErrorMsgSize = 128; |
173 | 271 |
174 Zone* zone_; | 272 Zone* zone_; |
175 TFBuilder* builder_; | 273 TFBuilder* builder_; |
176 const byte* base_; | 274 const byte* base_; |
177 TreeResult result_; | 275 TreeResult result_; |
178 | 276 |
179 SsaEnv* ssa_env_; | 277 SsaEnv* ssa_env_; |
180 FunctionEnv* function_env_; | |
181 | 278 |
182 ZoneVector<Tree*> trees_; | 279 ZoneVector<Tree*> trees_; |
183 ZoneVector<Production> stack_; | 280 ZoneVector<Production> stack_; |
184 ZoneVector<Block> blocks_; | 281 ZoneVector<Block> blocks_; |
185 ZoneVector<IfEnv> ifs_; | 282 ZoneVector<IfEnv> ifs_; |
186 | 283 |
187 inline bool build() { return builder_ && ssa_env_->go(); } | 284 inline bool build() { return builder_ && ssa_env_->go(); } |
188 | 285 |
189 void InitSsaEnv() { | 286 void InitSsaEnv() { |
190 FunctionSig* sig = function_env_->sig; | 287 FunctionSig* sig = function_env_->sig; |
(...skipping 1093 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1284 // Create an unreachable environment. | 1381 // Create an unreachable environment. |
1285 SsaEnv* UnreachableEnv() { | 1382 SsaEnv* UnreachableEnv() { |
1286 SsaEnv* result = reinterpret_cast<SsaEnv*>(zone_->New(sizeof(SsaEnv))); | 1383 SsaEnv* result = reinterpret_cast<SsaEnv*>(zone_->New(sizeof(SsaEnv))); |
1287 result->state = SsaEnv::kUnreachable; | 1384 result->state = SsaEnv::kUnreachable; |
1288 result->control = nullptr; | 1385 result->control = nullptr; |
1289 result->effect = nullptr; | 1386 result->effect = nullptr; |
1290 result->locals = nullptr; | 1387 result->locals = nullptr; |
1291 return result; | 1388 return result; |
1292 } | 1389 } |
1293 | 1390 |
1294 // Load an operand at [pc + 1]. | |
1295 template <typename V> | |
1296 V Operand(const byte* pc) { | |
1297 if ((limit_ - pc) < static_cast<int>(1 + sizeof(V))) { | |
1298 const char* msg = "Expected operand following opcode"; | |
1299 switch (sizeof(V)) { | |
1300 case 1: | |
1301 msg = "Expected 1-byte operand following opcode"; | |
1302 break; | |
1303 case 2: | |
1304 msg = "Expected 2-byte operand following opcode"; | |
1305 break; | |
1306 case 4: | |
1307 msg = "Expected 4-byte operand following opcode"; | |
1308 break; | |
1309 default: | |
1310 break; | |
1311 } | |
1312 error(pc, msg); | |
1313 return -1; | |
1314 } | |
1315 return *reinterpret_cast<const V*>(pc + 1); | |
1316 } | |
1317 | |
1318 int EnvironmentCount() { | 1391 int EnvironmentCount() { |
1319 if (builder_) return static_cast<int>(function_env_->GetLocalCount()); | 1392 if (builder_) return static_cast<int>(function_env_->GetLocalCount()); |
1320 return 0; // if we aren't building a graph, don't bother with SSA renaming. | 1393 return 0; // if we aren't building a graph, don't bother with SSA renaming. |
1321 } | 1394 } |
1322 | 1395 |
1323 LocalType LocalOperand(const byte* pc, uint32_t* index, int* length) { | |
1324 *index = UnsignedLEB128Operand(pc, length); | |
1325 if (function_env_->IsValidLocal(*index)) { | |
1326 return function_env_->GetLocalType(*index); | |
1327 } | |
1328 error(pc, "invalid local variable index"); | |
1329 return kAstStmt; | |
1330 } | |
1331 | |
1332 LocalType GlobalOperand(const byte* pc, uint32_t* index, int* length) { | |
1333 *index = UnsignedLEB128Operand(pc, length); | |
1334 if (function_env_->module->IsValidGlobal(*index)) { | |
1335 return WasmOpcodes::LocalTypeFor( | |
1336 function_env_->module->GetGlobalType(*index)); | |
1337 } | |
1338 error(pc, "invalid global variable index"); | |
1339 return kAstStmt; | |
1340 } | |
1341 | |
1342 FunctionSig* FunctionSigOperand(const byte* pc, uint32_t* index, | |
1343 int* length) { | |
1344 *index = UnsignedLEB128Operand(pc, length); | |
1345 if (function_env_->module->IsValidFunction(*index)) { | |
1346 return function_env_->module->GetFunctionSignature(*index); | |
1347 } | |
1348 error(pc, "invalid function index"); | |
1349 return nullptr; | |
1350 } | |
1351 | |
1352 FunctionSig* SigOperand(const byte* pc, uint32_t* index, int* length) { | |
1353 *index = UnsignedLEB128Operand(pc, length); | |
1354 if (function_env_->module->IsValidSignature(*index)) { | |
1355 return function_env_->module->GetSignature(*index); | |
1356 } | |
1357 error(pc, "invalid signature index"); | |
1358 return nullptr; | |
1359 } | |
1360 | |
1361 uint32_t UnsignedLEB128Operand(const byte* pc, int* length) { | |
1362 uint32_t result = 0; | |
1363 ReadUnsignedLEB128ErrorCode error_code = | |
1364 ReadUnsignedLEB128Operand(pc + 1, limit_, length, &result); | |
1365 if (error_code == kInvalidLEB128) error(pc, "invalid LEB128 varint"); | |
1366 if (error_code == kMissingLEB128) error(pc, "expected LEB128 varint"); | |
1367 (*length)++; | |
1368 return result; | |
1369 } | |
1370 | |
1371 void MemoryAccessOperand(const byte* pc, int* length, uint32_t* offset) { | |
1372 byte bitfield = Operand<uint8_t>(pc); | |
1373 if (MemoryAccess::OffsetField::decode(bitfield)) { | |
1374 *offset = UnsignedLEB128Operand(pc + 1, length); | |
1375 (*length)++; // to account for the memory access byte | |
1376 } else { | |
1377 *offset = 0; | |
1378 *length = 2; | |
1379 } | |
1380 } | |
1381 | |
1382 virtual void onFirstError() { | 1396 virtual void onFirstError() { |
1383 limit_ = start_; // Terminate decoding loop. | 1397 limit_ = start_; // Terminate decoding loop. |
1384 builder_ = nullptr; // Don't build any more nodes. | 1398 builder_ = nullptr; // Don't build any more nodes. |
1385 #if DEBUG | 1399 #if DEBUG |
1386 PrintStackForDebugging(); | 1400 PrintStackForDebugging(); |
1387 #endif | 1401 #endif |
1388 } | 1402 } |
1389 | 1403 |
1390 #if DEBUG | 1404 #if DEBUG |
1391 void PrintStackForDebugging() { PrintProduction(0); } | 1405 void PrintStackForDebugging() { PrintProduction(0); } |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1469 if (ptr == end && (b & 0x80)) { | 1483 if (ptr == end && (b & 0x80)) { |
1470 return kInvalidLEB128; | 1484 return kInvalidLEB128; |
1471 } else if (*length == 0) { | 1485 } else if (*length == 0) { |
1472 return kMissingLEB128; | 1486 return kMissingLEB128; |
1473 } else { | 1487 } else { |
1474 return kNoError; | 1488 return kNoError; |
1475 } | 1489 } |
1476 } | 1490 } |
1477 | 1491 |
1478 | 1492 |
| 1493 // TODO(titzer): move this into WasmDecoder and bounds check accesses. |
1479 int OpcodeLength(const byte* pc) { | 1494 int OpcodeLength(const byte* pc) { |
1480 switch (static_cast<WasmOpcode>(*pc)) { | 1495 switch (static_cast<WasmOpcode>(*pc)) { |
1481 #define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name: | 1496 #define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name: |
1482 FOREACH_LOAD_MEM_OPCODE(DECLARE_OPCODE_CASE) | 1497 FOREACH_LOAD_MEM_OPCODE(DECLARE_OPCODE_CASE) |
1483 FOREACH_STORE_MEM_OPCODE(DECLARE_OPCODE_CASE) | 1498 FOREACH_STORE_MEM_OPCODE(DECLARE_OPCODE_CASE) |
1484 #undef DECLARE_OPCODE_CASE | 1499 #undef DECLARE_OPCODE_CASE |
1485 { | 1500 { |
1486 // Loads and stores have an optional offset. | 1501 // Loads and stores have an optional offset. |
1487 byte bitfield = pc[1]; | 1502 byte bitfield = pc[1]; |
1488 if (MemoryAccess::OffsetField::decode(bitfield)) { | 1503 if (MemoryAccess::OffsetField::decode(bitfield)) { |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1520 uint16_t table_count = *reinterpret_cast<const uint16_t*>(pc + 3); | 1535 uint16_t table_count = *reinterpret_cast<const uint16_t*>(pc + 3); |
1521 return 5 + table_count * 2; | 1536 return 5 + table_count * 2; |
1522 } | 1537 } |
1523 | 1538 |
1524 default: | 1539 default: |
1525 return 1; | 1540 return 1; |
1526 } | 1541 } |
1527 } | 1542 } |
1528 | 1543 |
1529 | 1544 |
| 1545 // TODO(titzer): move this into WasmDecoder and bounds check accesses. |
1530 int OpcodeArity(FunctionEnv* env, const byte* pc) { | 1546 int OpcodeArity(FunctionEnv* env, const byte* pc) { |
1531 #define DECLARE_ARITY(name, ...) \ | 1547 #define DECLARE_ARITY(name, ...) \ |
1532 static const LocalType kTypes_##name[] = {__VA_ARGS__}; \ | 1548 static const LocalType kTypes_##name[] = {__VA_ARGS__}; \ |
1533 static const int kArity_##name = \ | 1549 static const int kArity_##name = \ |
1534 static_cast<int>(arraysize(kTypes_##name) - 1); | 1550 static_cast<int>(arraysize(kTypes_##name) - 1); |
1535 | 1551 |
1536 FOREACH_SIGNATURE(DECLARE_ARITY); | 1552 FOREACH_SIGNATURE(DECLARE_ARITY); |
1537 #undef DECLARE_ARITY | 1553 #undef DECLARE_ARITY |
1538 | 1554 |
1539 switch (static_cast<WasmOpcode>(*pc)) { | 1555 switch (static_cast<WasmOpcode>(*pc)) { |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1588 FOREACH_STORE_MEM_OPCODE(DECLARE_OPCODE_CASE) | 1604 FOREACH_STORE_MEM_OPCODE(DECLARE_OPCODE_CASE) |
1589 FOREACH_MISC_MEM_OPCODE(DECLARE_OPCODE_CASE) | 1605 FOREACH_MISC_MEM_OPCODE(DECLARE_OPCODE_CASE) |
1590 FOREACH_SIMPLE_OPCODE(DECLARE_OPCODE_CASE) | 1606 FOREACH_SIMPLE_OPCODE(DECLARE_OPCODE_CASE) |
1591 #undef DECLARE_OPCODE_CASE | 1607 #undef DECLARE_OPCODE_CASE |
1592 } | 1608 } |
1593 UNREACHABLE(); | 1609 UNREACHABLE(); |
1594 return 0; | 1610 return 0; |
1595 } | 1611 } |
1596 | 1612 |
1597 | 1613 |
| 1614 |
1598 void PrintAst(FunctionEnv* env, const byte* start, const byte* end) { | 1615 void PrintAst(FunctionEnv* env, const byte* start, const byte* end) { |
1599 const byte* pc = start; | 1616 const byte* pc = start; |
1600 std::vector<int> arity_stack; | 1617 std::vector<int> arity_stack; |
1601 while (pc < end) { | 1618 while (pc < end) { |
1602 int arity = OpcodeArity(env, pc); | 1619 int arity = OpcodeArity(env, pc); |
1603 size_t length = OpcodeLength(pc); | 1620 size_t length = OpcodeLength(pc); |
1604 | 1621 |
1605 for (auto arity : arity_stack) { | 1622 for (auto arity : arity_stack) { |
1606 printf(" "); | 1623 printf(" "); |
1607 USE(arity); | 1624 USE(arity); |
1608 } | 1625 } |
1609 | 1626 |
1610 WasmOpcode opcode = static_cast<WasmOpcode>(*pc); | 1627 WasmOpcode opcode = static_cast<WasmOpcode>(*pc); |
1611 printf("k%s,", WasmOpcodes::OpcodeName(opcode)); | 1628 printf("k%s,", WasmOpcodes::OpcodeName(opcode)); |
1612 | 1629 |
1613 for (size_t i = 1; i < length; i++) { | 1630 for (size_t i = 1; i < length; i++) { |
1614 printf(" 0x%02x,", pc[i]); | 1631 printf(" 0x%02x,", pc[i]); |
1615 } | 1632 } |
1616 pc += length; | 1633 pc += length; |
1617 printf("\n"); | 1634 printf("\n"); |
1618 | 1635 |
1619 arity_stack.push_back(arity); | 1636 arity_stack.push_back(arity); |
1620 while (arity_stack.back() == 0) { | 1637 while (arity_stack.back() == 0) { |
1621 arity_stack.pop_back(); | 1638 arity_stack.pop_back(); |
1622 if (arity_stack.empty()) break; | 1639 if (arity_stack.empty()) break; |
1623 arity_stack.back()--; | 1640 arity_stack.back()--; |
1624 } | 1641 } |
1625 } | 1642 } |
1626 } | 1643 } |
| 1644 |
| 1645 |
| 1646 // Analyzes loop bodies for static assignments to locals, which helps in |
| 1647 // reducing the number of phis introduced at loop headers. |
| 1648 class LoopAssignmentAnalyzer : public WasmDecoder { |
| 1649 public: |
| 1650 LoopAssignmentAnalyzer(Zone* zone, FunctionEnv* function_env) : zone_(zone) { |
| 1651 function_env_ = function_env; |
| 1652 } |
| 1653 |
| 1654 BitVector* Analyze(const byte* pc, const byte* limit) { |
| 1655 Decoder::Reset(pc, limit); |
| 1656 if (pc_ >= limit_) return nullptr; |
| 1657 if (*pc_ != kExprLoop) return nullptr; |
| 1658 |
| 1659 BitVector* assigned = |
| 1660 new (zone_) BitVector(function_env_->total_locals, zone_); |
| 1661 // Keep a stack to model the nesting of expressions. |
| 1662 std::vector<int> arity_stack; |
| 1663 arity_stack.push_back(OpcodeArity(function_env_, pc_)); |
| 1664 pc_ += OpcodeLength(pc_); |
| 1665 |
| 1666 // Iteratively process all AST nodes nested inside the loop. |
| 1667 while (pc_ < limit_) { |
| 1668 WasmOpcode opcode = static_cast<WasmOpcode>(*pc_); |
| 1669 int arity = 0; |
| 1670 int length = 1; |
| 1671 if (opcode == kExprSetLocal) { |
| 1672 uint32_t index; |
| 1673 LocalOperand(pc_, &index, &length); |
| 1674 if (assigned->length() > 0 && |
| 1675 static_cast<int>(index) < assigned->length()) { |
| 1676 // Unverified code might have an out-of-bounds index. |
| 1677 assigned->Add(index); |
| 1678 } |
| 1679 arity = 1; |
| 1680 } else { |
| 1681 arity = OpcodeArity(function_env_, pc_); |
| 1682 length = OpcodeLength(pc_); |
| 1683 } |
| 1684 |
| 1685 pc_ += length; |
| 1686 arity_stack.push_back(arity); |
| 1687 while (arity_stack.back() == 0) { |
| 1688 arity_stack.pop_back(); |
| 1689 if (arity_stack.empty()) return assigned; // reached end of loop |
| 1690 arity_stack.back()--; |
| 1691 } |
| 1692 } |
| 1693 return assigned; |
| 1694 } |
| 1695 |
| 1696 private: |
| 1697 Zone* zone_; |
| 1698 }; |
| 1699 |
| 1700 |
| 1701 BitVector* AnalyzeLoopAssignmentForTesting(Zone* zone, FunctionEnv* env, |
| 1702 const byte* start, const byte* end) { |
| 1703 LoopAssignmentAnalyzer analyzer(zone, env); |
| 1704 return analyzer.Analyze(start, end); |
| 1705 } |
| 1706 |
1627 } // namespace wasm | 1707 } // namespace wasm |
1628 } // namespace internal | 1708 } // namespace internal |
1629 } // namespace v8 | 1709 } // namespace v8 |
OLD | NEW |