Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(252)

Side by Side Diff: src/wasm/wasm-interpreter.cc

Issue 2649533002: [wasm] Implement stepping in wasm code (Closed)
Patch Set: Rebase Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/wasm/wasm-interpreter.h ('k') | src/wasm/wasm-objects.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2016 the V8 project authors. All rights reserved. 1 // Copyright 2016 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/wasm/wasm-interpreter.h" 5 #include "src/wasm/wasm-interpreter.h"
6 6
7 #include "src/utils.h" 7 #include "src/utils.h"
8 #include "src/wasm/decoder.h" 8 #include "src/wasm/decoder.h"
9 #include "src/wasm/function-body-decoder.h" 9 #include "src/wasm/function-body-decoder.h"
10 #include "src/wasm/wasm-external-refs.h" 10 #include "src/wasm/wasm-external-refs.h"
(...skipping 907 matching lines...) Expand 10 before | Expand all | Expand 10 after
918 918
919 namespace { 919 namespace {
920 // Responsible for executing code directly. 920 // Responsible for executing code directly.
921 class ThreadImpl { 921 class ThreadImpl {
922 public: 922 public:
923 ThreadImpl(Zone* zone, CodeMap* codemap, WasmInstance* instance) 923 ThreadImpl(Zone* zone, CodeMap* codemap, WasmInstance* instance)
924 : codemap_(codemap), 924 : codemap_(codemap),
925 instance_(instance), 925 instance_(instance),
926 stack_(zone), 926 stack_(zone),
927 frames_(zone), 927 frames_(zone),
928 blocks_(zone), 928 blocks_(zone) {}
929 state_(WasmInterpreter::STOPPED),
930 break_pc_(kInvalidPc),
931 trap_reason_(kTrapCount),
932 possible_nondeterminism_(false) {}
933 929
934 //========================================================================== 930 //==========================================================================
935 // Implementation of public interface for WasmInterpreter::Thread. 931 // Implementation of public interface for WasmInterpreter::Thread.
936 //========================================================================== 932 //==========================================================================
937 933
938 WasmInterpreter::State state() { return state_; } 934 WasmInterpreter::State state() { return state_; }
939 935
940 void PushFrame(const WasmFunction* function, WasmVal* args) { 936 void PushFrame(const WasmFunction* function, WasmVal* args) {
941 InterpreterCode* code = codemap()->FindCode(function); 937 InterpreterCode* code = codemap()->FindCode(function);
942 CHECK_NOT_NULL(code); 938 CHECK_NOT_NULL(code);
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
1007 if (state_ == WasmInterpreter::TRAPPED) return WasmVal(0xdeadbeef); 1003 if (state_ == WasmInterpreter::TRAPPED) return WasmVal(0xdeadbeef);
1008 CHECK_EQ(WasmInterpreter::FINISHED, state_); 1004 CHECK_EQ(WasmInterpreter::FINISHED, state_);
1009 CHECK_LT(static_cast<size_t>(index), stack_.size()); 1005 CHECK_LT(static_cast<size_t>(index), stack_.size());
1010 return stack_[index]; 1006 return stack_[index];
1011 } 1007 }
1012 1008
1013 pc_t GetBreakpointPc() { return break_pc_; } 1009 pc_t GetBreakpointPc() { return break_pc_; }
1014 1010
1015 bool PossibleNondeterminism() { return possible_nondeterminism_; } 1011 bool PossibleNondeterminism() { return possible_nondeterminism_; }
1016 1012
1013 void AddBreakFlags(uint8_t flags) { break_flags_ |= flags; }
1014
1015 void ClearBreakFlags() { break_flags_ = WasmInterpreter::BreakFlag::None; }
1016
1017 private: 1017 private:
1018 // Entries on the stack of functions being evaluated. 1018 // Entries on the stack of functions being evaluated.
1019 struct Frame { 1019 struct Frame {
1020 InterpreterCode* code; 1020 InterpreterCode* code;
1021 pc_t call_pc; 1021 pc_t call_pc;
1022 pc_t ret_pc; 1022 pc_t ret_pc;
1023 sp_t sp; 1023 sp_t sp;
1024 1024
1025 // Limit of parameters. 1025 // Limit of parameters.
1026 sp_t plimit() { return sp + code->function->sig->parameter_count(); } 1026 sp_t plimit() { return sp + code->function->sig->parameter_count(); }
1027 // Limit of locals. 1027 // Limit of locals.
1028 sp_t llimit() { return plimit() + code->locals.type_list.size(); } 1028 sp_t llimit() { return plimit() + code->locals.type_list.size(); }
1029 }; 1029 };
1030 1030
1031 struct Block { 1031 struct Block {
1032 pc_t pc; 1032 pc_t pc;
1033 sp_t sp; 1033 sp_t sp;
1034 size_t fp; 1034 size_t fp;
1035 unsigned arity; 1035 unsigned arity;
1036 }; 1036 };
1037 1037
1038 CodeMap* codemap_; 1038 CodeMap* codemap_;
1039 WasmInstance* instance_; 1039 WasmInstance* instance_;
1040 ZoneVector<WasmVal> stack_; 1040 ZoneVector<WasmVal> stack_;
1041 ZoneVector<Frame> frames_; 1041 ZoneVector<Frame> frames_;
1042 ZoneVector<Block> blocks_; 1042 ZoneVector<Block> blocks_;
1043 WasmInterpreter::State state_; 1043 WasmInterpreter::State state_ = WasmInterpreter::STOPPED;
1044 pc_t break_pc_; 1044 pc_t break_pc_ = kInvalidPc;
1045 TrapReason trap_reason_; 1045 TrapReason trap_reason_ = kTrapCount;
1046 bool possible_nondeterminism_; 1046 bool possible_nondeterminism_ = false;
1047 uint8_t break_flags_ = 0; // a combination of WasmInterpreter::BreakFlag
1047 1048
1048 CodeMap* codemap() { return codemap_; } 1049 CodeMap* codemap() { return codemap_; }
1049 WasmInstance* instance() { return instance_; } 1050 WasmInstance* instance() { return instance_; }
1050 const WasmModule* module() { return instance_->module; } 1051 const WasmModule* module() { return instance_->module; }
1051 1052
1052 void DoTrap(TrapReason trap, pc_t pc) { 1053 void DoTrap(TrapReason trap, pc_t pc) {
1053 state_ = WasmInterpreter::TRAPPED; 1054 state_ = WasmInterpreter::TRAPPED;
1054 trap_reason_ = trap; 1055 trap_reason_ = trap;
1055 CommitPc(pc); 1056 CommitPc(pc);
1056 } 1057 }
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after
1171 size_t pop_count = stack_.size() - dest - arity; 1172 size_t pop_count = stack_.size() - dest - arity;
1172 for (size_t i = 0; i < arity; i++) { 1173 for (size_t i = 0; i < arity; i++) {
1173 stack_[dest + i] = stack_[dest + pop_count + i]; 1174 stack_[dest + i] = stack_[dest + pop_count + i];
1174 } 1175 }
1175 stack_.resize(stack_.size() - pop_count); 1176 stack_.resize(stack_.size() - pop_count);
1176 } 1177 }
1177 1178
1178 void Execute(InterpreterCode* code, pc_t pc, int max) { 1179 void Execute(InterpreterCode* code, pc_t pc, int max) {
1179 Decoder decoder(code->start, code->end); 1180 Decoder decoder(code->start, code->end);
1180 pc_t limit = code->end - code->start; 1181 pc_t limit = code->end - code->start;
1181 while (true) { 1182 while (--max >= 0) {
1182 if (max-- <= 0) { 1183 #define PAUSE_IF_BREAK_FLAG(flag) \
1183 // Maximum number of instructions reached. 1184 if (V8_UNLIKELY(break_flags_ & WasmInterpreter::BreakFlag::flag)) max = 0;
1184 state_ = WasmInterpreter::PAUSED;
1185 return CommitPc(pc);
1186 }
1187 1185
1188 if (pc >= limit) { 1186 if (pc >= limit) {
1189 // Fell off end of code; do an implicit return. 1187 // Fell off end of code; do an implicit return.
1190 TRACE("@%-3zu: ImplicitReturn\n", pc); 1188 TRACE("@%-3zu: ImplicitReturn\n", pc);
1191 if (!DoReturn(&code, &pc, &limit, code->function->sig->return_count())) 1189 if (!DoReturn(&code, &pc, &limit, code->function->sig->return_count()))
1192 return; 1190 return;
1193 decoder.Reset(code->start, code->end); 1191 decoder.Reset(code->start, code->end);
1192 PAUSE_IF_BREAK_FLAG(AfterReturn);
1194 continue; 1193 continue;
1195 } 1194 }
1196 1195
1197 const char* skip = " "; 1196 const char* skip = " ";
1198 int len = 1; 1197 int len = 1;
1199 byte opcode = code->start[pc]; 1198 byte opcode = code->start[pc];
1200 byte orig = opcode; 1199 byte orig = opcode;
1201 if (opcode == kInternalBreakpoint) { 1200 if (V8_UNLIKELY(opcode == kInternalBreakpoint)) {
1202 orig = code->orig_start[pc]; 1201 orig = code->orig_start[pc];
1203 if (SkipBreakpoint(code, pc)) { 1202 if (SkipBreakpoint(code, pc)) {
1204 // skip breakpoint by switching on original code. 1203 // skip breakpoint by switching on original code.
1205 skip = "[skip] "; 1204 skip = "[skip] ";
1206 } else { 1205 } else {
1207 state_ = WasmInterpreter::PAUSED; 1206 state_ = WasmInterpreter::PAUSED;
1208 TRACE("@%-3zu: [break] %-24s:", pc, 1207 TRACE("@%-3zu: [break] %-24s:", pc,
1209 WasmOpcodes::OpcodeName(static_cast<WasmOpcode>(orig))); 1208 WasmOpcodes::OpcodeName(static_cast<WasmOpcode>(orig)));
1210 TraceValueStack(); 1209 TraceValueStack();
1211 TRACE("\n"); 1210 TRACE("\n");
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
1293 depth = iterator.next(); 1292 depth = iterator.next();
1294 } 1293 }
1295 len = key + DoBreak(code, pc + key, static_cast<size_t>(depth)); 1294 len = key + DoBreak(code, pc + key, static_cast<size_t>(depth));
1296 TRACE(" br[%u] => @%zu\n", key, pc + key + len); 1295 TRACE(" br[%u] => @%zu\n", key, pc + key + len);
1297 break; 1296 break;
1298 } 1297 }
1299 case kExprReturn: { 1298 case kExprReturn: {
1300 size_t arity = code->function->sig->return_count(); 1299 size_t arity = code->function->sig->return_count();
1301 if (!DoReturn(&code, &pc, &limit, arity)) return; 1300 if (!DoReturn(&code, &pc, &limit, arity)) return;
1302 decoder.Reset(code->start, code->end); 1301 decoder.Reset(code->start, code->end);
1302 PAUSE_IF_BREAK_FLAG(AfterReturn);
1303 continue; 1303 continue;
1304 } 1304 }
1305 case kExprUnreachable: { 1305 case kExprUnreachable: {
1306 DoTrap(kTrapUnreachable, pc); 1306 DoTrap(kTrapUnreachable, pc);
1307 return CommitPc(pc); 1307 return CommitPc(pc);
1308 } 1308 }
1309 case kExprEnd: { 1309 case kExprEnd: {
1310 blocks_.pop_back(); 1310 blocks_.pop_back();
1311 break; 1311 break;
1312 } 1312 }
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
1358 case kExprDrop: { 1358 case kExprDrop: {
1359 Pop(); 1359 Pop();
1360 break; 1360 break;
1361 } 1361 }
1362 case kExprCallFunction: { 1362 case kExprCallFunction: {
1363 CallFunctionOperand operand(&decoder, code->at(pc)); 1363 CallFunctionOperand operand(&decoder, code->at(pc));
1364 InterpreterCode* target = codemap()->GetCode(operand.index); 1364 InterpreterCode* target = codemap()->GetCode(operand.index);
1365 DoCall(target, &pc, pc + 1 + operand.length, &limit); 1365 DoCall(target, &pc, pc + 1 + operand.length, &limit);
1366 code = target; 1366 code = target;
1367 decoder.Reset(code->start, code->end); 1367 decoder.Reset(code->start, code->end);
1368 PAUSE_IF_BREAK_FLAG(AfterCall);
1368 continue; 1369 continue;
1369 } 1370 }
1370 case kExprCallIndirect: { 1371 case kExprCallIndirect: {
1371 CallIndirectOperand operand(&decoder, code->at(pc)); 1372 CallIndirectOperand operand(&decoder, code->at(pc));
1372 uint32_t entry_index = Pop().to<uint32_t>(); 1373 uint32_t entry_index = Pop().to<uint32_t>();
1373 // Assume only one table for now. 1374 // Assume only one table for now.
1374 DCHECK_LE(module()->function_tables.size(), 1u); 1375 DCHECK_LE(module()->function_tables.size(), 1u);
1375 InterpreterCode* target = codemap()->GetIndirectCode(0, entry_index); 1376 InterpreterCode* target = codemap()->GetIndirectCode(0, entry_index);
1376 if (target == nullptr) { 1377 if (target == nullptr) {
1377 return DoTrap(kTrapFuncInvalid, pc); 1378 return DoTrap(kTrapFuncInvalid, pc);
1378 } else if (target->function->sig_index != operand.index) { 1379 } else if (target->function->sig_index != operand.index) {
1379 // If not an exact match, we have to do a canonical check. 1380 // If not an exact match, we have to do a canonical check.
1380 // TODO(titzer): make this faster with some kind of caching? 1381 // TODO(titzer): make this faster with some kind of caching?
1381 const WasmIndirectFunctionTable* table = 1382 const WasmIndirectFunctionTable* table =
1382 &module()->function_tables[0]; 1383 &module()->function_tables[0];
1383 int function_key = table->map.Find(target->function->sig); 1384 int function_key = table->map.Find(target->function->sig);
1384 if (function_key < 0 || 1385 if (function_key < 0 ||
1385 (function_key != 1386 (function_key !=
1386 table->map.Find(module()->signatures[operand.index]))) { 1387 table->map.Find(module()->signatures[operand.index]))) {
1387 return DoTrap(kTrapFuncSigMismatch, pc); 1388 return DoTrap(kTrapFuncSigMismatch, pc);
1388 } 1389 }
1389 } 1390 }
1390 1391
1391 DoCall(target, &pc, pc + 1 + operand.length, &limit); 1392 DoCall(target, &pc, pc + 1 + operand.length, &limit);
1392 code = target; 1393 code = target;
1393 decoder.Reset(code->start, code->end); 1394 decoder.Reset(code->start, code->end);
1395 PAUSE_IF_BREAK_FLAG(AfterCall);
1394 continue; 1396 continue;
1395 } 1397 }
1396 case kExprGetGlobal: { 1398 case kExprGetGlobal: {
1397 GlobalIndexOperand operand(&decoder, code->at(pc)); 1399 GlobalIndexOperand operand(&decoder, code->at(pc));
1398 const WasmGlobal* global = &module()->globals[operand.index]; 1400 const WasmGlobal* global = &module()->globals[operand.index];
1399 byte* ptr = instance()->globals_start + global->offset; 1401 byte* ptr = instance()->globals_start + global->offset;
1400 ValueType type = global->type; 1402 ValueType type = global->type;
1401 WasmVal val; 1403 WasmVal val;
1402 if (type == kWasmI32) { 1404 if (type == kWasmI32) {
1403 val = WasmVal(*reinterpret_cast<int32_t*>(ptr)); 1405 val = WasmVal(*reinterpret_cast<int32_t*>(ptr));
(...skipping 225 matching lines...) Expand 10 before | Expand all | Expand 10 after
1629 #undef EXECUTE_OTHER_UNOP_NAN 1631 #undef EXECUTE_OTHER_UNOP_NAN
1630 1632
1631 default: 1633 default:
1632 V8_Fatal(__FILE__, __LINE__, "Unknown or unimplemented opcode #%d:%s", 1634 V8_Fatal(__FILE__, __LINE__, "Unknown or unimplemented opcode #%d:%s",
1633 code->start[pc], OpcodeName(code->start[pc])); 1635 code->start[pc], OpcodeName(code->start[pc]));
1634 UNREACHABLE(); 1636 UNREACHABLE();
1635 } 1637 }
1636 1638
1637 pc += len; 1639 pc += len;
1638 } 1640 }
1639 UNREACHABLE(); // above decoding loop should run forever. 1641 state_ = WasmInterpreter::PAUSED;
1642 CommitPc(pc);
1640 } 1643 }
1641 1644
1642 WasmVal Pop() { 1645 WasmVal Pop() {
1643 DCHECK_GT(stack_.size(), 0); 1646 DCHECK_GT(stack_.size(), 0);
1644 DCHECK_GT(frames_.size(), 0); 1647 DCHECK_GT(frames_.size(), 0);
1645 DCHECK_GT(stack_.size(), frames_.back().llimit()); // can't pop into locals 1648 DCHECK_GT(stack_.size(), frames_.back().llimit()); // can't pop into locals
1646 WasmVal val = stack_.back(); 1649 WasmVal val = stack_.back();
1647 stack_.pop_back(); 1650 stack_.pop_back();
1648 return val; 1651 return val;
1649 } 1652 }
(...skipping 19 matching lines...) Expand all
1669 1672
1670 void TraceStack(const char* phase, pc_t pc) { 1673 void TraceStack(const char* phase, pc_t pc) {
1671 if (FLAG_trace_wasm_interpreter) { 1674 if (FLAG_trace_wasm_interpreter) {
1672 PrintF("%s @%zu", phase, pc); 1675 PrintF("%s @%zu", phase, pc);
1673 UNIMPLEMENTED(); 1676 UNIMPLEMENTED();
1674 PrintF("\n"); 1677 PrintF("\n");
1675 } 1678 }
1676 } 1679 }
1677 1680
1678 void TraceValueStack() { 1681 void TraceValueStack() {
1682 #ifdef DEBUG
1679 Frame* top = frames_.size() > 0 ? &frames_.back() : nullptr; 1683 Frame* top = frames_.size() > 0 ? &frames_.back() : nullptr;
1680 sp_t sp = top ? top->sp : 0; 1684 sp_t sp = top ? top->sp : 0;
1681 sp_t plimit = top ? top->plimit() : 0; 1685 sp_t plimit = top ? top->plimit() : 0;
1682 sp_t llimit = top ? top->llimit() : 0; 1686 sp_t llimit = top ? top->llimit() : 0;
1683 if (FLAG_trace_wasm_interpreter) { 1687 if (FLAG_trace_wasm_interpreter) {
1684 for (size_t i = sp; i < stack_.size(); ++i) { 1688 for (size_t i = sp; i < stack_.size(); ++i) {
1685 if (i < plimit) 1689 if (i < plimit)
1686 PrintF(" p%zu:", i); 1690 PrintF(" p%zu:", i);
1687 else if (i < llimit) 1691 else if (i < llimit)
1688 PrintF(" l%zu:", i); 1692 PrintF(" l%zu:", i);
(...skipping 15 matching lines...) Expand all
1704 break; 1708 break;
1705 case kWasmStmt: 1709 case kWasmStmt:
1706 PrintF("void"); 1710 PrintF("void");
1707 break; 1711 break;
1708 default: 1712 default:
1709 UNREACHABLE(); 1713 UNREACHABLE();
1710 break; 1714 break;
1711 } 1715 }
1712 } 1716 }
1713 } 1717 }
1718 #endif // DEBUG
1714 } 1719 }
1715 }; 1720 };
1716 1721
1717 // Converters between WasmInterpreter::Thread and WasmInterpreter::ThreadImpl. 1722 // Converters between WasmInterpreter::Thread and WasmInterpreter::ThreadImpl.
1718 // Thread* is the public interface, without knowledge of the object layout. 1723 // Thread* is the public interface, without knowledge of the object layout.
1719 // This cast is potentially risky, but as long as we always cast it back before 1724 // This cast is potentially risky, but as long as we always cast it back before
1720 // accessing any data, it should be fine. UBSan is not complaining. 1725 // accessing any data, it should be fine. UBSan is not complaining.
1721 WasmInterpreter::Thread* ToThread(ThreadImpl* impl) { 1726 WasmInterpreter::Thread* ToThread(ThreadImpl* impl) {
1722 return reinterpret_cast<WasmInterpreter::Thread*>(impl); 1727 return reinterpret_cast<WasmInterpreter::Thread*>(impl);
1723 } 1728 }
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
1763 return InterpretedFrame(function, pc, fp, sp); 1768 return InterpretedFrame(function, pc, fp, sp);
1764 }; 1769 };
1765 return ToImpl(this)->GetMutableFrame(index, frame_cons); 1770 return ToImpl(this)->GetMutableFrame(index, frame_cons);
1766 } 1771 }
1767 WasmVal WasmInterpreter::Thread::GetReturnValue(int index) { 1772 WasmVal WasmInterpreter::Thread::GetReturnValue(int index) {
1768 return ToImpl(this)->GetReturnValue(index); 1773 return ToImpl(this)->GetReturnValue(index);
1769 } 1774 }
1770 bool WasmInterpreter::Thread::PossibleNondeterminism() { 1775 bool WasmInterpreter::Thread::PossibleNondeterminism() {
1771 return ToImpl(this)->PossibleNondeterminism(); 1776 return ToImpl(this)->PossibleNondeterminism();
1772 } 1777 }
1778 void WasmInterpreter::Thread::AddBreakFlags(uint8_t flags) {
1779 ToImpl(this)->AddBreakFlags(flags);
1780 }
1781 void WasmInterpreter::Thread::ClearBreakFlags() {
1782 ToImpl(this)->ClearBreakFlags();
1783 }
1773 1784
1774 //============================================================================ 1785 //============================================================================
1775 // The implementation details of the interpreter. 1786 // The implementation details of the interpreter.
1776 //============================================================================ 1787 //============================================================================
1777 class WasmInterpreterInternals : public ZoneObject { 1788 class WasmInterpreterInternals : public ZoneObject {
1778 public: 1789 public:
1779 WasmInstance* instance_; 1790 WasmInstance* instance_;
1780 // Create a copy of the module bytes for the interpreter, since the passed 1791 // Create a copy of the module bytes for the interpreter, since the passed
1781 // pointer might be invalidated after constructing the interpreter. 1792 // pointer might be invalidated after constructing the interpreter.
1782 const ZoneVector<uint8_t> module_bytes_; 1793 const ZoneVector<uint8_t> module_bytes_;
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after
1910 return none; 1921 return none;
1911 } 1922 }
1912 1923
1913 void InterpretedFrame::SetLocalVal(int index, WasmVal val) { UNIMPLEMENTED(); } 1924 void InterpretedFrame::SetLocalVal(int index, WasmVal val) { UNIMPLEMENTED(); }
1914 1925
1915 void InterpretedFrame::SetExprVal(int pc, WasmVal val) { UNIMPLEMENTED(); } 1926 void InterpretedFrame::SetExprVal(int pc, WasmVal val) { UNIMPLEMENTED(); }
1916 1927
1917 } // namespace wasm 1928 } // namespace wasm
1918 } // namespace internal 1929 } // namespace internal
1919 } // namespace v8 1930 } // namespace v8
OLDNEW
« no previous file with comments | « src/wasm/wasm-interpreter.h ('k') | src/wasm/wasm-objects.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698