| OLD | NEW |
| 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 901 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 912 code->orig_start = start; | 912 code->orig_start = start; |
| 913 code->orig_end = end; | 913 code->orig_end = end; |
| 914 code->start = const_cast<byte*>(start); | 914 code->start = const_cast<byte*>(start); |
| 915 code->end = const_cast<byte*>(end); | 915 code->end = const_cast<byte*>(end); |
| 916 Preprocess(code); | 916 Preprocess(code); |
| 917 return true; | 917 return true; |
| 918 } | 918 } |
| 919 }; | 919 }; |
| 920 | 920 |
| 921 // Responsible for executing code directly. | 921 // Responsible for executing code directly. |
| 922 class ThreadImpl : public WasmInterpreter::Thread { | 922 class WasmInterpreter::ThreadImpl : public ZoneObject { |
| 923 public: | 923 public: |
| 924 ThreadImpl(Zone* zone, CodeMap* codemap, WasmInstance* instance) | 924 ThreadImpl(Zone* zone, CodeMap* codemap, WasmInstance* instance) |
| 925 : codemap_(codemap), | 925 : codemap_(codemap), |
| 926 instance_(instance), | 926 instance_(instance), |
| 927 stack_(zone), | 927 stack_(zone), |
| 928 frames_(zone), | 928 frames_(zone), |
| 929 blocks_(zone), | 929 blocks_(zone), |
| 930 state_(WasmInterpreter::STOPPED), | 930 state_(WasmInterpreter::STOPPED), |
| 931 break_pc_(kInvalidPc), | 931 break_pc_(kInvalidPc), |
| 932 trap_reason_(kTrapCount), | 932 trap_reason_(kTrapCount), |
| 933 possible_nondeterminism_(false) {} | 933 possible_nondeterminism_(false) {} |
| 934 | 934 |
| 935 virtual ~ThreadImpl() {} | 935 ~ThreadImpl() {} |
| 936 | 936 |
| 937 //========================================================================== | 937 //========================================================================== |
| 938 // Implementation of public interface for WasmInterpreter::Thread. | 938 // Implementation of public interface for WasmInterpreter::Thread. |
| 939 //========================================================================== | 939 //========================================================================== |
| 940 | 940 |
| 941 virtual WasmInterpreter::State state() { return state_; } | 941 WasmInterpreter::State state() { return state_; } |
| 942 | 942 |
| 943 virtual void PushFrame(const WasmFunction* function, WasmVal* args) { | 943 void PushFrame(const WasmFunction* function, WasmVal* args) { |
| 944 InterpreterCode* code = codemap()->FindCode(function); | 944 InterpreterCode* code = codemap()->FindCode(function); |
| 945 CHECK_NOT_NULL(code); | 945 CHECK_NOT_NULL(code); |
| 946 frames_.push_back({code, 0, 0, stack_.size()}); | 946 frames_.push_back({code, 0, 0, stack_.size()}); |
| 947 for (size_t i = 0; i < function->sig->parameter_count(); ++i) { | 947 for (size_t i = 0; i < function->sig->parameter_count(); ++i) { |
| 948 stack_.push_back(args[i]); | 948 stack_.push_back(args[i]); |
| 949 } | 949 } |
| 950 frames_.back().ret_pc = InitLocals(code); | 950 frames_.back().ret_pc = InitLocals(code); |
| 951 blocks_.push_back( | 951 blocks_.push_back( |
| 952 {0, stack_.size(), frames_.size(), | 952 {0, stack_.size(), frames_.size(), |
| 953 static_cast<uint32_t>(code->function->sig->return_count())}); | 953 static_cast<uint32_t>(code->function->sig->return_count())}); |
| 954 TRACE(" => PushFrame(#%u @%zu)\n", code->function->func_index, | 954 TRACE(" => PushFrame(#%u @%zu)\n", code->function->func_index, |
| 955 frames_.back().ret_pc); | 955 frames_.back().ret_pc); |
| 956 } | 956 } |
| 957 | 957 |
| 958 virtual WasmInterpreter::State Run() { | 958 WasmInterpreter::State Run() { |
| 959 do { | 959 do { |
| 960 TRACE(" => Run()\n"); | 960 TRACE(" => Run()\n"); |
| 961 if (state_ == WasmInterpreter::STOPPED || | 961 if (state_ == WasmInterpreter::STOPPED || |
| 962 state_ == WasmInterpreter::PAUSED) { | 962 state_ == WasmInterpreter::PAUSED) { |
| 963 state_ = WasmInterpreter::RUNNING; | 963 state_ = WasmInterpreter::RUNNING; |
| 964 Execute(frames_.back().code, frames_.back().ret_pc, kRunSteps); | 964 Execute(frames_.back().code, frames_.back().ret_pc, kRunSteps); |
| 965 } | 965 } |
| 966 } while (state_ == WasmInterpreter::STOPPED); | 966 } while (state_ == WasmInterpreter::STOPPED); |
| 967 return state_; | 967 return state_; |
| 968 } | 968 } |
| 969 | 969 |
| 970 virtual WasmInterpreter::State Step() { | 970 WasmInterpreter::State Step() { |
| 971 TRACE(" => Step()\n"); | 971 TRACE(" => Step()\n"); |
| 972 if (state_ == WasmInterpreter::STOPPED || | 972 if (state_ == WasmInterpreter::STOPPED || |
| 973 state_ == WasmInterpreter::PAUSED) { | 973 state_ == WasmInterpreter::PAUSED) { |
| 974 state_ = WasmInterpreter::RUNNING; | 974 state_ = WasmInterpreter::RUNNING; |
| 975 Execute(frames_.back().code, frames_.back().ret_pc, 1); | 975 Execute(frames_.back().code, frames_.back().ret_pc, 1); |
| 976 } | 976 } |
| 977 return state_; | 977 return state_; |
| 978 } | 978 } |
| 979 | 979 |
| 980 virtual void Pause() { UNIMPLEMENTED(); } | 980 void Pause() { UNIMPLEMENTED(); } |
| 981 | 981 |
| 982 virtual void Reset() { | 982 void Reset() { |
| 983 TRACE("----- RESET -----\n"); | 983 TRACE("----- RESET -----\n"); |
| 984 stack_.clear(); | 984 stack_.clear(); |
| 985 frames_.clear(); | 985 frames_.clear(); |
| 986 state_ = WasmInterpreter::STOPPED; | 986 state_ = WasmInterpreter::STOPPED; |
| 987 trap_reason_ = kTrapCount; | 987 trap_reason_ = kTrapCount; |
| 988 possible_nondeterminism_ = false; | 988 possible_nondeterminism_ = false; |
| 989 } | 989 } |
| 990 | 990 |
| 991 virtual int GetFrameCount() { return static_cast<int>(frames_.size()); } | 991 int GetFrameCount() { return static_cast<int>(frames_.size()); } |
| 992 | 992 |
| 993 virtual const WasmFrame* GetFrame(int index) { | 993 const WasmFrame* GetFrame(int index) { |
| 994 UNIMPLEMENTED(); | 994 UNIMPLEMENTED(); |
| 995 return nullptr; | 995 return nullptr; |
| 996 } | 996 } |
| 997 | 997 |
| 998 virtual WasmFrame* GetMutableFrame(int index) { | 998 WasmFrame* GetMutableFrame(int index) { |
| 999 UNIMPLEMENTED(); | 999 UNIMPLEMENTED(); |
| 1000 return nullptr; | 1000 return nullptr; |
| 1001 } | 1001 } |
| 1002 | 1002 |
| 1003 virtual WasmVal GetReturnValue(int index) { | 1003 WasmVal GetReturnValue(int index) { |
| 1004 if (state_ == WasmInterpreter::TRAPPED) return WasmVal(0xdeadbeef); | 1004 if (state_ == WasmInterpreter::TRAPPED) return WasmVal(0xdeadbeef); |
| 1005 CHECK_EQ(WasmInterpreter::FINISHED, state_); | 1005 CHECK_EQ(WasmInterpreter::FINISHED, state_); |
| 1006 CHECK_LT(static_cast<size_t>(index), stack_.size()); | 1006 CHECK_LT(static_cast<size_t>(index), stack_.size()); |
| 1007 return stack_[index]; | 1007 return stack_[index]; |
| 1008 } | 1008 } |
| 1009 | 1009 |
| 1010 virtual pc_t GetBreakpointPc() { return break_pc_; } | 1010 pc_t GetBreakpointPc() { return break_pc_; } |
| 1011 | 1011 |
| 1012 virtual bool PossibleNondeterminism() { return possible_nondeterminism_; } | 1012 bool PossibleNondeterminism() { return possible_nondeterminism_; } |
| 1013 | |
| 1014 bool Terminated() { | |
| 1015 return state_ == WasmInterpreter::TRAPPED || | |
| 1016 state_ == WasmInterpreter::FINISHED; | |
| 1017 } | |
| 1018 | 1013 |
| 1019 private: | 1014 private: |
| 1020 // Entries on the stack of functions being evaluated. | 1015 // Entries on the stack of functions being evaluated. |
| 1021 struct Frame { | 1016 struct Frame { |
| 1022 InterpreterCode* code; | 1017 InterpreterCode* code; |
| 1023 pc_t call_pc; | 1018 pc_t call_pc; |
| 1024 pc_t ret_pc; | 1019 pc_t ret_pc; |
| 1025 sp_t sp; | 1020 sp_t sp; |
| 1026 | 1021 |
| 1027 // Limit of parameters. | 1022 // Limit of parameters. |
| (...skipping 669 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1697 default: | 1692 default: |
| 1698 UNREACHABLE(); | 1693 UNREACHABLE(); |
| 1699 break; | 1694 break; |
| 1700 } | 1695 } |
| 1701 } | 1696 } |
| 1702 } | 1697 } |
| 1703 } | 1698 } |
| 1704 }; | 1699 }; |
| 1705 | 1700 |
| 1706 //============================================================================ | 1701 //============================================================================ |
| 1702 // Forwarding functions of WasmInterpreter::Thread (pimpl idiom). |
| 1703 //============================================================================ |
| 1704 WasmInterpreter::Thread::Thread(ThreadImpl* impl) : impl_(impl) {} |
| 1705 WasmInterpreter::State WasmInterpreter::Thread::state() { |
| 1706 return impl_->state(); |
| 1707 } |
| 1708 void WasmInterpreter::Thread::PushFrame(const WasmFunction* function, |
| 1709 WasmVal* args) { |
| 1710 return impl_->PushFrame(function, args); |
| 1711 } |
| 1712 WasmInterpreter::State WasmInterpreter::Thread::Run() { return impl_->Run(); } |
| 1713 WasmInterpreter::State WasmInterpreter::Thread::Step() { return impl_->Step(); } |
| 1714 void WasmInterpreter::Thread::Pause() { return impl_->Pause(); } |
| 1715 void WasmInterpreter::Thread::Reset() { return impl_->Reset(); } |
| 1716 pc_t WasmInterpreter::Thread::GetBreakpointPc() { |
| 1717 return impl_->GetBreakpointPc(); |
| 1718 } |
| 1719 int WasmInterpreter::Thread::GetFrameCount() { return impl_->GetFrameCount(); } |
| 1720 const WasmFrame* WasmInterpreter::Thread::GetFrame(int index) { |
| 1721 return impl_->GetFrame(index); |
| 1722 } |
| 1723 WasmFrame* WasmInterpreter::Thread::GetMutableFrame(int index) { |
| 1724 return impl_->GetMutableFrame(index); |
| 1725 } |
| 1726 WasmVal WasmInterpreter::Thread::GetReturnValue(int index) { |
| 1727 return impl_->GetReturnValue(index); |
| 1728 } |
| 1729 bool WasmInterpreter::Thread::PossibleNondeterminism() { |
| 1730 return impl_->PossibleNondeterminism(); |
| 1731 } |
| 1732 |
| 1733 //============================================================================ |
| 1707 // The implementation details of the interpreter. | 1734 // The implementation details of the interpreter. |
| 1708 //============================================================================ | 1735 //============================================================================ |
| 1709 class WasmInterpreterInternals : public ZoneObject { | 1736 class WasmInterpreterInternals : public ZoneObject { |
| 1710 public: | 1737 public: |
| 1711 WasmInstance* instance_; | 1738 WasmInstance* instance_; |
| 1712 // Create a copy of the module bytes for the interpreter, since the passed | 1739 // Create a copy of the module bytes for the interpreter, since the passed |
| 1713 // pointer might be invalidated after constructing the interpreter. | 1740 // pointer might be invalidated after constructing the interpreter. |
| 1714 const ZoneVector<uint8_t> module_bytes_; | 1741 const ZoneVector<uint8_t> module_bytes_; |
| 1715 CodeMap codemap_; | 1742 CodeMap codemap_; |
| 1716 ZoneVector<ThreadImpl*> threads_; | 1743 ZoneVector<WasmInterpreter::Thread> threads_; |
| 1717 | 1744 |
| 1718 WasmInterpreterInternals(Zone* zone, const ModuleBytesEnv& env) | 1745 WasmInterpreterInternals(Zone* zone, const ModuleBytesEnv& env) |
| 1719 : instance_(env.instance), | 1746 : instance_(env.instance), |
| 1720 module_bytes_(env.module_bytes.start(), env.module_bytes.end(), zone), | 1747 module_bytes_(env.module_bytes.start(), env.module_bytes.end(), zone), |
| 1721 codemap_(env.instance ? env.instance->module : nullptr, | 1748 codemap_(env.instance ? env.instance->module : nullptr, |
| 1722 module_bytes_.data(), zone), | 1749 module_bytes_.data(), zone), |
| 1723 threads_(zone) { | 1750 threads_(zone) { |
| 1724 threads_.push_back(new ThreadImpl(zone, &codemap_, env.instance)); | 1751 threads_.push_back(WasmInterpreter::Thread( |
| 1752 new (zone) WasmInterpreter::ThreadImpl(zone, &codemap_, env.instance))); |
| 1725 } | 1753 } |
| 1726 | 1754 |
| 1727 void Delete() { | 1755 void Delete() { threads_.clear(); } |
| 1728 // TODO(titzer): CFI doesn't like threads in the ZoneVector. | |
| 1729 for (auto t : threads_) delete t; | |
| 1730 threads_.resize(0); | |
| 1731 } | |
| 1732 }; | 1756 }; |
| 1733 | 1757 |
| 1734 //============================================================================ | 1758 //============================================================================ |
| 1735 // Implementation of the public interface of the interpreter. | 1759 // Implementation of the public interface of the interpreter. |
| 1736 //============================================================================ | 1760 //============================================================================ |
| 1737 WasmInterpreter::WasmInterpreter(const ModuleBytesEnv& env, | 1761 WasmInterpreter::WasmInterpreter(const ModuleBytesEnv& env, |
| 1738 AccountingAllocator* allocator) | 1762 AccountingAllocator* allocator) |
| 1739 : zone_(allocator, ZONE_NAME), | 1763 : zone_(allocator, ZONE_NAME), |
| 1740 internals_(new (&zone_) WasmInterpreterInternals(&zone_, env)) {} | 1764 internals_(new (&zone_) WasmInterpreterInternals(&zone_, env)) {} |
| 1741 | 1765 |
| 1742 WasmInterpreter::~WasmInterpreter() { internals_->Delete(); } | 1766 WasmInterpreter::~WasmInterpreter() { internals_->Delete(); } |
| 1743 | 1767 |
| 1744 void WasmInterpreter::Run() { internals_->threads_[0]->Run(); } | 1768 void WasmInterpreter::Run() { internals_->threads_[0].Run(); } |
| 1745 | 1769 |
| 1746 void WasmInterpreter::Pause() { internals_->threads_[0]->Pause(); } | 1770 void WasmInterpreter::Pause() { internals_->threads_[0].Pause(); } |
| 1747 | 1771 |
| 1748 bool WasmInterpreter::SetBreakpoint(const WasmFunction* function, pc_t pc, | 1772 bool WasmInterpreter::SetBreakpoint(const WasmFunction* function, pc_t pc, |
| 1749 bool enabled) { | 1773 bool enabled) { |
| 1750 InterpreterCode* code = internals_->codemap_.FindCode(function); | 1774 InterpreterCode* code = internals_->codemap_.FindCode(function); |
| 1751 if (!code) return false; | 1775 if (!code) return false; |
| 1752 size_t size = static_cast<size_t>(code->end - code->start); | 1776 size_t size = static_cast<size_t>(code->end - code->start); |
| 1753 // Check bounds for {pc}. | 1777 // Check bounds for {pc}. |
| 1754 if (pc < code->locals.encoded_size || pc >= size) return false; | 1778 if (pc < code->locals.encoded_size || pc >= size) return false; |
| 1755 // Make a copy of the code before enabling a breakpoint. | 1779 // Make a copy of the code before enabling a breakpoint. |
| 1756 if (enabled && code->orig_start == code->start) { | 1780 if (enabled && code->orig_start == code->start) { |
| (...skipping 24 matching lines...) Expand all Loading... |
| 1781 UNIMPLEMENTED(); | 1805 UNIMPLEMENTED(); |
| 1782 return false; | 1806 return false; |
| 1783 } | 1807 } |
| 1784 | 1808 |
| 1785 int WasmInterpreter::GetThreadCount() { | 1809 int WasmInterpreter::GetThreadCount() { |
| 1786 return 1; // only one thread for now. | 1810 return 1; // only one thread for now. |
| 1787 } | 1811 } |
| 1788 | 1812 |
| 1789 WasmInterpreter::Thread* WasmInterpreter::GetThread(int id) { | 1813 WasmInterpreter::Thread* WasmInterpreter::GetThread(int id) { |
| 1790 CHECK_EQ(0, id); // only one thread for now. | 1814 CHECK_EQ(0, id); // only one thread for now. |
| 1791 return internals_->threads_[id]; | 1815 return &internals_->threads_[id]; |
| 1792 } | 1816 } |
| 1793 | 1817 |
| 1794 WasmVal WasmInterpreter::GetLocalVal(const WasmFrame* frame, int index) { | 1818 WasmVal WasmInterpreter::GetLocalVal(const WasmFrame* frame, int index) { |
| 1795 CHECK_GE(index, 0); | 1819 CHECK_GE(index, 0); |
| 1796 UNIMPLEMENTED(); | 1820 UNIMPLEMENTED(); |
| 1797 WasmVal none; | 1821 WasmVal none; |
| 1798 none.type = kWasmStmt; | 1822 none.type = kWasmStmt; |
| 1799 return none; | 1823 return none; |
| 1800 } | 1824 } |
| 1801 | 1825 |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1839 | 1863 |
| 1840 ControlTransferMap WasmInterpreter::ComputeControlTransfersForTesting( | 1864 ControlTransferMap WasmInterpreter::ComputeControlTransfersForTesting( |
| 1841 Zone* zone, const byte* start, const byte* end) { | 1865 Zone* zone, const byte* start, const byte* end) { |
| 1842 ControlTransfers targets(zone, nullptr, start, end); | 1866 ControlTransfers targets(zone, nullptr, start, end); |
| 1843 return targets.map_; | 1867 return targets.map_; |
| 1844 } | 1868 } |
| 1845 | 1869 |
| 1846 } // namespace wasm | 1870 } // namespace wasm |
| 1847 } // namespace internal | 1871 } // namespace internal |
| 1848 } // namespace v8 | 1872 } // namespace v8 |
| OLD | NEW |