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) {} | |
bradnelson
2016/01/22 06:28:33
Are you planning to pull this out into it's own fi
| |
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 (index < assigned->length()) assigned->Add(index); | |
ahaas
2016/01/22 06:53:26
How could index >= assigned-length() even be possi
titzer
2016/01/23 16:20:37
This is because I plan to use it while decoding, w
| |
1675 arity = 1; | |
bradnelson
2016/01/22 06:28:33
Why bake in the arity again?
Pull the else block o
titzer
2016/01/23 16:20:37
Ah, just a micro-optimization.
| |
1676 } else { | |
1677 arity = OpcodeArity(function_env_, pc_); | |
1678 length = OpcodeLength(pc_); | |
1679 } | |
1680 | |
1681 pc_ += length; | |
1682 arity_stack.push_back(arity); | |
1683 while (arity_stack.back() == 0) { | |
1684 arity_stack.pop_back(); | |
1685 if (arity_stack.empty()) return assigned; // reached end of loop | |
1686 arity_stack.back()--; | |
1687 } | |
1688 } | |
1689 return assigned; | |
bradnelson
2016/01/22 06:28:33
In a well formed program, shouldn't we always hit
titzer
2016/01/23 16:20:37
As mentioned above, I'm assuming not assuming the
| |
1690 } | |
1691 | |
1692 private: | |
1693 Zone* zone_; | |
1694 }; | |
1695 | |
1696 | |
1697 BitVector* AnalyzeLoopAssignmentForTesting(Zone* zone, FunctionEnv* env, | |
1698 const byte* start, const byte* end) { | |
1699 LoopAssignmentAnalyzer analyzer(zone, env); | |
1700 return analyzer.Analyze(start, end); | |
1701 } | |
1702 | |
1627 } // namespace wasm | 1703 } // namespace wasm |
1628 } // namespace internal | 1704 } // namespace internal |
1629 } // namespace v8 | 1705 } // namespace v8 |
OLD | NEW |