| 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/ast-decoder.h" | 8 #include "src/wasm/ast-decoder.h" |
| 9 #include "src/wasm/decoder.h" | 9 #include "src/wasm/decoder.h" |
| 10 #include "src/wasm/wasm-external-refs.h" | 10 #include "src/wasm/wasm-external-refs.h" |
| (...skipping 704 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 715 | 715 |
| 716 static const int kRunSteps = 1000; | 716 static const int kRunSteps = 1000; |
| 717 | 717 |
| 718 // A helper class to compute the control transfers for each bytecode offset. | 718 // A helper class to compute the control transfers for each bytecode offset. |
| 719 // Control transfers allow Br, BrIf, BrTable, If, Else, and End bytecodes to | 719 // Control transfers allow Br, BrIf, BrTable, If, Else, and End bytecodes to |
| 720 // be directly executed without the need to dynamically track blocks. | 720 // be directly executed without the need to dynamically track blocks. |
| 721 class ControlTransfers : public ZoneObject { | 721 class ControlTransfers : public ZoneObject { |
| 722 public: | 722 public: |
| 723 ControlTransferMap map_; | 723 ControlTransferMap map_; |
| 724 | 724 |
| 725 ControlTransfers(Zone* zone, ModuleEnv* env, AstLocalDecls* locals, | 725 ControlTransfers(Zone* zone, size_t locals_encoded_size, const byte* start, |
| 726 const byte* start, const byte* end) | 726 const byte* end) |
| 727 : map_(zone) { | 727 : map_(zone) { |
| 728 // A control reference including from PC, from value depth, and whether |
| 729 // a value is explicitly passed (e.g. br/br_if/br_table with value). |
| 730 struct CRef { |
| 731 const byte* pc; |
| 732 sp_t value_depth; |
| 733 bool explicit_value; |
| 734 }; |
| 735 |
| 728 // Represents a control flow label. | 736 // Represents a control flow label. |
| 729 struct CLabel : public ZoneObject { | 737 struct CLabel : public ZoneObject { |
| 730 const byte* target; | 738 const byte* target; |
| 731 ZoneVector<const byte*> refs; | 739 size_t value_depth; |
| 740 ZoneVector<CRef> refs; |
| 732 | 741 |
| 733 explicit CLabel(Zone* zone) : target(nullptr), refs(zone) {} | 742 CLabel(Zone* zone, size_t v) |
| 743 : target(nullptr), value_depth(v), refs(zone) {} |
| 734 | 744 |
| 735 // Bind this label to the given PC. | 745 // Bind this label to the given PC. |
| 736 void Bind(ControlTransferMap* map, const byte* start, const byte* pc) { | 746 void Bind(ControlTransferMap* map, const byte* start, const byte* pc, |
| 747 bool expect_value) { |
| 737 DCHECK_NULL(target); | 748 DCHECK_NULL(target); |
| 738 target = pc; | 749 target = pc; |
| 739 for (auto from_pc : refs) { | 750 for (auto from : refs) { |
| 740 auto pcdiff = static_cast<pcdiff_t>(target - from_pc); | 751 auto pcdiff = static_cast<pcdiff_t>(target - from.pc); |
| 741 size_t offset = static_cast<size_t>(from_pc - start); | 752 auto spdiff = static_cast<spdiff_t>(from.value_depth - value_depth); |
| 742 (*map)[offset] = pcdiff; | 753 ControlTransfer::StackAction action = ControlTransfer::kNoAction; |
| 754 if (expect_value && !from.explicit_value) { |
| 755 action = spdiff == 0 ? ControlTransfer::kPushVoid |
| 756 : ControlTransfer::kPopAndRepush; |
| 757 } |
| 758 pc_t offset = static_cast<size_t>(from.pc - start); |
| 759 (*map)[offset] = {pcdiff, spdiff, action}; |
| 743 } | 760 } |
| 744 } | 761 } |
| 745 | 762 |
| 746 // Reference this label from the given location. | 763 // Reference this label from the given location. |
| 747 void Ref(ControlTransferMap* map, const byte* start, | 764 void Ref(ControlTransferMap* map, const byte* start, CRef from) { |
| 748 const byte* from_pc) { | 765 DCHECK_GE(from.value_depth, value_depth); |
| 749 if (target) { | 766 if (target) { |
| 750 // Target being bound before a reference means this is a loop. | 767 auto pcdiff = static_cast<pcdiff_t>(target - from.pc); |
| 751 DCHECK_EQ(kExprLoop, *target); | 768 auto spdiff = static_cast<spdiff_t>(from.value_depth - value_depth); |
| 752 auto pcdiff = static_cast<pcdiff_t>(target - from_pc); | 769 pc_t offset = static_cast<size_t>(from.pc - start); |
| 753 size_t offset = static_cast<size_t>(from_pc - start); | 770 (*map)[offset] = {pcdiff, spdiff, ControlTransfer::kNoAction}; |
| 754 (*map)[offset] = pcdiff; | |
| 755 } else { | 771 } else { |
| 756 refs.push_back(from_pc); | 772 refs.push_back(from); |
| 757 } | 773 } |
| 758 } | 774 } |
| 759 }; | 775 }; |
| 760 | 776 |
| 761 // An entry in the control stack. | 777 // An entry in the control stack. |
| 762 struct Control { | 778 struct Control { |
| 763 const byte* pc; | 779 const byte* pc; |
| 764 CLabel* end_label; | 780 CLabel* end_label; |
| 765 CLabel* else_label; | 781 CLabel* else_label; |
| 766 | 782 |
| 767 void Ref(ControlTransferMap* map, const byte* start, | 783 void Ref(ControlTransferMap* map, const byte* start, const byte* from_pc, |
| 768 const byte* from_pc) { | 784 size_t from_value_depth, bool explicit_value) { |
| 769 end_label->Ref(map, start, from_pc); | 785 end_label->Ref(map, start, {from_pc, from_value_depth, explicit_value}); |
| 770 } | 786 } |
| 771 }; | 787 }; |
| 772 | 788 |
| 773 // Compute the ControlTransfer map. | 789 // Compute the ControlTransfer map. |
| 774 // This algorithm maintains a stack of control constructs similar to the | 790 // This works by maintaining a stack of control constructs similar to the |
| 775 // AST decoder. The {control_stack} allows matching {br,br_if,br_table} | 791 // AST decoder. The {control_stack} allows matching {br,br_if,br_table} |
| 776 // bytecodes with their target, as well as determining whether the current | 792 // bytecodes with their target, as well as determining whether the current |
| 777 // bytecodes are within the true or false block of an else. | 793 // bytecodes are within the true or false block of an else. |
| 794 // The value stack depth is tracked as {value_depth} and is needed to |
| 795 // determine how many values to pop off the stack for explicit and |
| 796 // implicit control flow. |
| 797 |
| 778 std::vector<Control> control_stack; | 798 std::vector<Control> control_stack; |
| 779 CLabel* func_label = new (zone) CLabel(zone); | 799 size_t value_depth = 0; |
| 780 control_stack.push_back({start, func_label, nullptr}); | 800 for (BytecodeIterator i(start + locals_encoded_size, end); i.has_next(); |
| 781 for (BytecodeIterator i(start, end, locals); i.has_next(); i.next()) { | 801 i.next()) { |
| 782 WasmOpcode opcode = i.current(); | 802 WasmOpcode opcode = i.current(); |
| 783 TRACE("@%u: control %s\n", i.pc_offset(), | 803 TRACE("@%u: control %s (depth = %zu)\n", i.pc_offset(), |
| 784 WasmOpcodes::OpcodeName(opcode)); | 804 WasmOpcodes::OpcodeName(opcode), value_depth); |
| 785 switch (opcode) { | 805 switch (opcode) { |
| 786 case kExprBlock: { | 806 case kExprBlock: { |
| 787 TRACE("control @%u: Block\n", i.pc_offset()); | 807 TRACE("control @%u $%zu: Block\n", i.pc_offset(), value_depth); |
| 788 CLabel* label = new (zone) CLabel(zone); | 808 CLabel* label = new (zone) CLabel(zone, value_depth); |
| 789 control_stack.push_back({i.pc(), label, nullptr}); | 809 control_stack.push_back({i.pc(), label, nullptr}); |
| 790 break; | 810 break; |
| 791 } | 811 } |
| 792 case kExprLoop: { | 812 case kExprLoop: { |
| 793 TRACE("control @%u: Loop\n", i.pc_offset()); | 813 TRACE("control @%u $%zu: Loop\n", i.pc_offset(), value_depth); |
| 794 CLabel* label = new (zone) CLabel(zone); | 814 CLabel* label1 = new (zone) CLabel(zone, value_depth); |
| 795 control_stack.push_back({i.pc(), label, nullptr}); | 815 CLabel* label2 = new (zone) CLabel(zone, value_depth); |
| 796 label->Bind(&map_, start, i.pc()); | 816 control_stack.push_back({i.pc(), label1, nullptr}); |
| 817 control_stack.push_back({i.pc(), label2, nullptr}); |
| 818 label2->Bind(&map_, start, i.pc(), false); |
| 797 break; | 819 break; |
| 798 } | 820 } |
| 799 case kExprIf: { | 821 case kExprIf: { |
| 800 TRACE("control @%u: If\n", i.pc_offset()); | 822 TRACE("control @%u $%zu: If\n", i.pc_offset(), value_depth); |
| 801 CLabel* end_label = new (zone) CLabel(zone); | 823 value_depth--; |
| 802 CLabel* else_label = new (zone) CLabel(zone); | 824 CLabel* end_label = new (zone) CLabel(zone, value_depth); |
| 825 CLabel* else_label = new (zone) CLabel(zone, value_depth); |
| 803 control_stack.push_back({i.pc(), end_label, else_label}); | 826 control_stack.push_back({i.pc(), end_label, else_label}); |
| 804 else_label->Ref(&map_, start, i.pc()); | 827 else_label->Ref(&map_, start, {i.pc(), value_depth, false}); |
| 805 break; | 828 break; |
| 806 } | 829 } |
| 807 case kExprElse: { | 830 case kExprElse: { |
| 808 Control* c = &control_stack.back(); | 831 Control* c = &control_stack.back(); |
| 809 TRACE("control @%u: Else\n", i.pc_offset()); | 832 TRACE("control @%u $%zu: Else\n", i.pc_offset(), value_depth); |
| 810 c->end_label->Ref(&map_, start, i.pc()); | 833 c->end_label->Ref(&map_, start, {i.pc(), value_depth, false}); |
| 834 value_depth = c->end_label->value_depth; |
| 811 DCHECK_NOT_NULL(c->else_label); | 835 DCHECK_NOT_NULL(c->else_label); |
| 812 c->else_label->Bind(&map_, start, i.pc() + 1); | 836 c->else_label->Bind(&map_, start, i.pc() + 1, false); |
| 813 c->else_label = nullptr; | 837 c->else_label = nullptr; |
| 814 break; | 838 break; |
| 815 } | 839 } |
| 816 case kExprEnd: { | 840 case kExprEnd: { |
| 817 Control* c = &control_stack.back(); | 841 Control* c = &control_stack.back(); |
| 818 TRACE("control @%u: End\n", i.pc_offset()); | 842 TRACE("control @%u $%zu: End\n", i.pc_offset(), value_depth); |
| 819 if (c->end_label->target) { | 843 if (c->end_label->target) { |
| 820 // only loops have bound labels. | 844 // only loops have bound labels. |
| 821 DCHECK_EQ(kExprLoop, *c->pc); | 845 DCHECK_EQ(kExprLoop, *c->pc); |
| 822 } else { | 846 control_stack.pop_back(); |
| 823 if (c->else_label) c->else_label->Bind(&map_, start, i.pc()); | 847 c = &control_stack.back(); |
| 824 c->end_label->Bind(&map_, start, i.pc() + 1); | |
| 825 } | 848 } |
| 849 if (c->else_label) |
| 850 c->else_label->Bind(&map_, start, i.pc() + 1, true); |
| 851 c->end_label->Ref(&map_, start, {i.pc(), value_depth, false}); |
| 852 c->end_label->Bind(&map_, start, i.pc() + 1, true); |
| 853 value_depth = c->end_label->value_depth + 1; |
| 826 control_stack.pop_back(); | 854 control_stack.pop_back(); |
| 827 break; | 855 break; |
| 828 } | 856 } |
| 829 case kExprBr: { | 857 case kExprBr: { |
| 830 BreakDepthOperand operand(&i, i.pc()); | 858 BreakDepthOperand operand(&i, i.pc()); |
| 831 TRACE("control @%u: Br[depth=%u]\n", i.pc_offset(), operand.depth); | 859 TRACE("control @%u $%zu: Br[arity=%u, depth=%u]\n", i.pc_offset(), |
| 832 Control* c = &control_stack[control_stack.size() - operand.depth - 1]; | 860 value_depth, operand.arity, operand.depth); |
| 833 c->Ref(&map_, start, i.pc()); | 861 value_depth -= operand.arity; |
| 862 control_stack[control_stack.size() - operand.depth - 1].Ref( |
| 863 &map_, start, i.pc(), value_depth, operand.arity > 0); |
| 864 value_depth++; |
| 834 break; | 865 break; |
| 835 } | 866 } |
| 836 case kExprBrIf: { | 867 case kExprBrIf: { |
| 837 BreakDepthOperand operand(&i, i.pc()); | 868 BreakDepthOperand operand(&i, i.pc()); |
| 838 TRACE("control @%u: BrIf[depth=%u]\n", i.pc_offset(), operand.depth); | 869 TRACE("control @%u $%zu: BrIf[arity=%u, depth=%u]\n", i.pc_offset(), |
| 839 Control* c = &control_stack[control_stack.size() - operand.depth - 1]; | 870 value_depth, operand.arity, operand.depth); |
| 840 c->Ref(&map_, start, i.pc()); | 871 value_depth -= (operand.arity + 1); |
| 872 control_stack[control_stack.size() - operand.depth - 1].Ref( |
| 873 &map_, start, i.pc(), value_depth, operand.arity > 0); |
| 874 value_depth++; |
| 841 break; | 875 break; |
| 842 } | 876 } |
| 843 case kExprBrTable: { | 877 case kExprBrTable: { |
| 844 BranchTableOperand operand(&i, i.pc()); | 878 BranchTableOperand operand(&i, i.pc()); |
| 845 BranchTableIterator iterator(&i, operand); | 879 TRACE("control @%u $%zu: BrTable[arity=%u count=%u]\n", i.pc_offset(), |
| 846 TRACE("control @%u: BrTable[count=%u]\n", i.pc_offset(), | 880 value_depth, operand.arity, operand.table_count); |
| 847 operand.table_count); | 881 value_depth -= (operand.arity + 1); |
| 848 while (iterator.has_next()) { | 882 for (uint32_t j = 0; j < operand.table_count + 1; ++j) { |
| 849 uint32_t j = iterator.cur_index(); | 883 uint32_t target = operand.read_entry(&i, j); |
| 850 uint32_t target = iterator.next(); | 884 control_stack[control_stack.size() - target - 1].Ref( |
| 851 Control* c = &control_stack[control_stack.size() - target - 1]; | 885 &map_, start, i.pc() + j, value_depth, operand.arity > 0); |
| 852 c->Ref(&map_, start, i.pc() + j); | |
| 853 } | 886 } |
| 887 value_depth++; |
| 854 break; | 888 break; |
| 855 } | 889 } |
| 856 default: { | 890 default: { |
| 891 value_depth = value_depth - OpcodeArity(i.pc(), end) + 1; |
| 857 break; | 892 break; |
| 858 } | 893 } |
| 859 } | 894 } |
| 860 } | 895 } |
| 861 if (!func_label->target) func_label->Bind(&map_, start, end); | |
| 862 } | 896 } |
| 863 | 897 |
| 864 pcdiff_t Lookup(pc_t from) { | 898 ControlTransfer Lookup(pc_t from) { |
| 865 auto result = map_.find(from); | 899 auto result = map_.find(from); |
| 866 if (result == map_.end()) { | 900 if (result == map_.end()) { |
| 867 V8_Fatal(__FILE__, __LINE__, "no control target for pc %zu", from); | 901 V8_Fatal(__FILE__, __LINE__, "no control target for pc %zu", from); |
| 868 } | 902 } |
| 869 return result->second; | 903 return result->second; |
| 870 } | 904 } |
| 871 }; | 905 }; |
| 872 | 906 |
| 873 // Code and metadata needed to execute a function. | 907 // Code and metadata needed to execute a function. |
| 874 struct InterpreterCode { | 908 struct InterpreterCode { |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 924 if (entry_index >= table->values.size()) return nullptr; | 958 if (entry_index >= table->values.size()) return nullptr; |
| 925 uint32_t index = table->values[entry_index]; | 959 uint32_t index = table->values[entry_index]; |
| 926 if (index >= interpreter_code_.size()) return nullptr; | 960 if (index >= interpreter_code_.size()) return nullptr; |
| 927 return GetCode(index); | 961 return GetCode(index); |
| 928 } | 962 } |
| 929 | 963 |
| 930 InterpreterCode* Preprocess(InterpreterCode* code) { | 964 InterpreterCode* Preprocess(InterpreterCode* code) { |
| 931 if (code->targets == nullptr && code->start) { | 965 if (code->targets == nullptr && code->start) { |
| 932 // Compute the control targets map and the local declarations. | 966 // Compute the control targets map and the local declarations. |
| 933 CHECK(DecodeLocalDecls(code->locals, code->start, code->end)); | 967 CHECK(DecodeLocalDecls(code->locals, code->start, code->end)); |
| 934 ModuleEnv env = {module_, nullptr, kWasmOrigin}; | 968 code->targets = |
| 935 code->targets = new (zone_) ControlTransfers( | 969 new (zone_) ControlTransfers(zone_, code->locals.decls_encoded_size, |
| 936 zone_, &env, &code->locals, code->orig_start, code->orig_end); | 970 code->orig_start, code->orig_end); |
| 937 } | 971 } |
| 938 return code; | 972 return code; |
| 939 } | 973 } |
| 940 | 974 |
| 941 int AddFunction(const WasmFunction* function, const byte* code_start, | 975 int AddFunction(const WasmFunction* function, const byte* code_start, |
| 942 const byte* code_end) { | 976 const byte* code_end) { |
| 943 InterpreterCode code = { | 977 InterpreterCode code = { |
| 944 function, AstLocalDecls(zone_), code_start, | 978 function, AstLocalDecls(zone_), code_start, |
| 945 code_end, const_cast<byte*>(code_start), const_cast<byte*>(code_end), | 979 code_end, const_cast<byte*>(code_start), const_cast<byte*>(code_end), |
| 946 nullptr}; | 980 nullptr}; |
| (...skipping 18 matching lines...) Expand all Loading... |
| 965 }; | 999 }; |
| 966 | 1000 |
| 967 // Responsible for executing code directly. | 1001 // Responsible for executing code directly. |
| 968 class ThreadImpl : public WasmInterpreter::Thread { | 1002 class ThreadImpl : public WasmInterpreter::Thread { |
| 969 public: | 1003 public: |
| 970 ThreadImpl(Zone* zone, CodeMap* codemap, WasmModuleInstance* instance) | 1004 ThreadImpl(Zone* zone, CodeMap* codemap, WasmModuleInstance* instance) |
| 971 : codemap_(codemap), | 1005 : codemap_(codemap), |
| 972 instance_(instance), | 1006 instance_(instance), |
| 973 stack_(zone), | 1007 stack_(zone), |
| 974 frames_(zone), | 1008 frames_(zone), |
| 975 blocks_(zone), | |
| 976 state_(WasmInterpreter::STOPPED), | 1009 state_(WasmInterpreter::STOPPED), |
| 977 break_pc_(kInvalidPc), | 1010 break_pc_(kInvalidPc), |
| 978 trap_reason_(kTrapCount) {} | 1011 trap_reason_(kTrapCount) {} |
| 979 | 1012 |
| 980 virtual ~ThreadImpl() {} | 1013 virtual ~ThreadImpl() {} |
| 981 | 1014 |
| 982 //========================================================================== | 1015 //========================================================================== |
| 983 // Implementation of public interface for WasmInterpreter::Thread. | 1016 // Implementation of public interface for WasmInterpreter::Thread. |
| 984 //========================================================================== | 1017 //========================================================================== |
| 985 | 1018 |
| 986 virtual WasmInterpreter::State state() { return state_; } | 1019 virtual WasmInterpreter::State state() { return state_; } |
| 987 | 1020 |
| 988 virtual void PushFrame(const WasmFunction* function, WasmVal* args) { | 1021 virtual void PushFrame(const WasmFunction* function, WasmVal* args) { |
| 989 InterpreterCode* code = codemap()->FindCode(function); | 1022 InterpreterCode* code = codemap()->FindCode(function); |
| 990 CHECK_NOT_NULL(code); | 1023 CHECK_NOT_NULL(code); |
| 991 frames_.push_back({code, 0, 0, stack_.size()}); | 1024 frames_.push_back({code, 0, 0, stack_.size()}); |
| 992 for (size_t i = 0; i < function->sig->parameter_count(); ++i) { | 1025 for (size_t i = 0; i < function->sig->parameter_count(); ++i) { |
| 993 stack_.push_back(args[i]); | 1026 stack_.push_back(args[i]); |
| 994 } | 1027 } |
| 995 frames_.back().ret_pc = InitLocals(code); | 1028 frames_.back().ret_pc = InitLocals(code); |
| 996 blocks_.push_back( | |
| 997 {0, stack_.size(), frames_.size(), | |
| 998 static_cast<uint32_t>(code->function->sig->return_count())}); | |
| 999 TRACE(" => PushFrame(#%u @%zu)\n", code->function->func_index, | 1029 TRACE(" => PushFrame(#%u @%zu)\n", code->function->func_index, |
| 1000 frames_.back().ret_pc); | 1030 frames_.back().ret_pc); |
| 1001 } | 1031 } |
| 1002 | 1032 |
| 1003 virtual WasmInterpreter::State Run() { | 1033 virtual WasmInterpreter::State Run() { |
| 1004 do { | 1034 do { |
| 1005 TRACE(" => Run()\n"); | 1035 TRACE(" => Run()\n"); |
| 1006 if (state_ == WasmInterpreter::STOPPED || | 1036 if (state_ == WasmInterpreter::STOPPED || |
| 1007 state_ == WasmInterpreter::PAUSED) { | 1037 state_ == WasmInterpreter::PAUSED) { |
| 1008 state_ = WasmInterpreter::RUNNING; | 1038 state_ = WasmInterpreter::RUNNING; |
| (...skipping 28 matching lines...) Expand all Loading... |
| 1037 virtual const WasmFrame* GetFrame(int index) { | 1067 virtual const WasmFrame* GetFrame(int index) { |
| 1038 UNIMPLEMENTED(); | 1068 UNIMPLEMENTED(); |
| 1039 return nullptr; | 1069 return nullptr; |
| 1040 } | 1070 } |
| 1041 | 1071 |
| 1042 virtual WasmFrame* GetMutableFrame(int index) { | 1072 virtual WasmFrame* GetMutableFrame(int index) { |
| 1043 UNIMPLEMENTED(); | 1073 UNIMPLEMENTED(); |
| 1044 return nullptr; | 1074 return nullptr; |
| 1045 } | 1075 } |
| 1046 | 1076 |
| 1047 virtual WasmVal GetReturnValue(int index) { | 1077 virtual WasmVal GetReturnValue() { |
| 1048 if (state_ == WasmInterpreter::TRAPPED) return WasmVal(0xdeadbeef); | 1078 if (state_ == WasmInterpreter::TRAPPED) return WasmVal(0xdeadbeef); |
| 1049 CHECK_EQ(WasmInterpreter::FINISHED, state_); | 1079 CHECK_EQ(WasmInterpreter::FINISHED, state_); |
| 1050 CHECK_LT(static_cast<size_t>(index), stack_.size()); | 1080 CHECK_EQ(1, stack_.size()); |
| 1051 return stack_[index]; | 1081 return stack_[0]; |
| 1052 } | 1082 } |
| 1053 | 1083 |
| 1054 virtual pc_t GetBreakpointPc() { return break_pc_; } | 1084 virtual pc_t GetBreakpointPc() { return break_pc_; } |
| 1055 | 1085 |
| 1056 bool Terminated() { | 1086 bool Terminated() { |
| 1057 return state_ == WasmInterpreter::TRAPPED || | 1087 return state_ == WasmInterpreter::TRAPPED || |
| 1058 state_ == WasmInterpreter::FINISHED; | 1088 state_ == WasmInterpreter::FINISHED; |
| 1059 } | 1089 } |
| 1060 | 1090 |
| 1061 private: | 1091 private: |
| 1062 // Entries on the stack of functions being evaluated. | 1092 // Entries on the stack of functions being evaluated. |
| 1063 struct Frame { | 1093 struct Frame { |
| 1064 InterpreterCode* code; | 1094 InterpreterCode* code; |
| 1065 pc_t call_pc; | 1095 pc_t call_pc; |
| 1066 pc_t ret_pc; | 1096 pc_t ret_pc; |
| 1067 sp_t sp; | 1097 sp_t sp; |
| 1068 | 1098 |
| 1069 // Limit of parameters. | 1099 // Limit of parameters. |
| 1070 sp_t plimit() { return sp + code->function->sig->parameter_count(); } | 1100 sp_t plimit() { return sp + code->function->sig->parameter_count(); } |
| 1071 // Limit of locals. | 1101 // Limit of locals. |
| 1072 sp_t llimit() { return plimit() + code->locals.total_local_count; } | 1102 sp_t llimit() { return plimit() + code->locals.total_local_count; } |
| 1073 }; | 1103 }; |
| 1074 | 1104 |
| 1075 struct Block { | |
| 1076 pc_t pc; | |
| 1077 sp_t sp; | |
| 1078 size_t fp; | |
| 1079 unsigned arity; | |
| 1080 }; | |
| 1081 | |
| 1082 CodeMap* codemap_; | 1105 CodeMap* codemap_; |
| 1083 WasmModuleInstance* instance_; | 1106 WasmModuleInstance* instance_; |
| 1084 ZoneVector<WasmVal> stack_; | 1107 ZoneVector<WasmVal> stack_; |
| 1085 ZoneVector<Frame> frames_; | 1108 ZoneVector<Frame> frames_; |
| 1086 ZoneVector<Block> blocks_; | |
| 1087 WasmInterpreter::State state_; | 1109 WasmInterpreter::State state_; |
| 1088 pc_t break_pc_; | 1110 pc_t break_pc_; |
| 1089 TrapReason trap_reason_; | 1111 TrapReason trap_reason_; |
| 1090 | 1112 |
| 1091 CodeMap* codemap() { return codemap_; } | 1113 CodeMap* codemap() { return codemap_; } |
| 1092 WasmModuleInstance* instance() { return instance_; } | 1114 WasmModuleInstance* instance() { return instance_; } |
| 1093 const WasmModule* module() { return instance_->module; } | 1115 const WasmModule* module() { return instance_->module; } |
| 1094 | 1116 |
| 1095 void DoTrap(TrapReason trap, pc_t pc) { | 1117 void DoTrap(TrapReason trap, pc_t pc) { |
| 1096 state_ = WasmInterpreter::TRAPPED; | 1118 state_ = WasmInterpreter::TRAPPED; |
| 1097 trap_reason_ = trap; | 1119 trap_reason_ = trap; |
| 1098 CommitPc(pc); | 1120 CommitPc(pc); |
| 1099 } | 1121 } |
| 1100 | 1122 |
| 1101 // Push a frame with arguments already on the stack. | 1123 // Push a frame with arguments already on the stack. |
| 1102 void PushFrame(InterpreterCode* code, pc_t call_pc, pc_t ret_pc) { | 1124 void PushFrame(InterpreterCode* code, pc_t call_pc, pc_t ret_pc) { |
| 1103 CHECK_NOT_NULL(code); | 1125 CHECK_NOT_NULL(code); |
| 1104 DCHECK(!frames_.empty()); | 1126 DCHECK(!frames_.empty()); |
| 1105 frames_.back().call_pc = call_pc; | 1127 frames_.back().call_pc = call_pc; |
| 1106 frames_.back().ret_pc = ret_pc; | 1128 frames_.back().ret_pc = ret_pc; |
| 1107 size_t arity = code->function->sig->parameter_count(); | 1129 size_t arity = code->function->sig->parameter_count(); |
| 1108 DCHECK_GE(stack_.size(), arity); | 1130 DCHECK_GE(stack_.size(), arity); |
| 1109 // The parameters will overlap the arguments already on the stack. | 1131 // The parameters will overlap the arguments already on the stack. |
| 1110 frames_.push_back({code, 0, 0, stack_.size() - arity}); | 1132 frames_.push_back({code, 0, 0, stack_.size() - arity}); |
| 1111 blocks_.push_back( | |
| 1112 {0, stack_.size(), frames_.size(), | |
| 1113 static_cast<uint32_t>(code->function->sig->return_count())}); | |
| 1114 frames_.back().ret_pc = InitLocals(code); | 1133 frames_.back().ret_pc = InitLocals(code); |
| 1115 TRACE(" => push func#%u @%zu\n", code->function->func_index, | 1134 TRACE(" => push func#%u @%zu\n", code->function->func_index, |
| 1116 frames_.back().ret_pc); | 1135 frames_.back().ret_pc); |
| 1117 } | 1136 } |
| 1118 | 1137 |
| 1119 pc_t InitLocals(InterpreterCode* code) { | 1138 pc_t InitLocals(InterpreterCode* code) { |
| 1120 for (auto p : code->locals.local_types) { | 1139 for (auto p : code->locals.local_types) { |
| 1121 WasmVal val; | 1140 WasmVal val; |
| 1122 switch (p.first) { | 1141 switch (p.first) { |
| 1123 case kAstI32: | 1142 case kAstI32: |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1142 } | 1161 } |
| 1143 | 1162 |
| 1144 void CommitPc(pc_t pc) { | 1163 void CommitPc(pc_t pc) { |
| 1145 if (!frames_.empty()) { | 1164 if (!frames_.empty()) { |
| 1146 frames_.back().ret_pc = pc; | 1165 frames_.back().ret_pc = pc; |
| 1147 } | 1166 } |
| 1148 } | 1167 } |
| 1149 | 1168 |
| 1150 bool SkipBreakpoint(InterpreterCode* code, pc_t pc) { | 1169 bool SkipBreakpoint(InterpreterCode* code, pc_t pc) { |
| 1151 if (pc == break_pc_) { | 1170 if (pc == break_pc_) { |
| 1152 // Skip the previously hit breakpoint when resuming. | |
| 1153 break_pc_ = kInvalidPc; | 1171 break_pc_ = kInvalidPc; |
| 1154 return true; | 1172 return true; |
| 1155 } | 1173 } |
| 1156 return false; | 1174 return false; |
| 1157 } | 1175 } |
| 1158 | 1176 |
| 1159 int LookupTarget(InterpreterCode* code, pc_t pc) { | 1177 bool DoReturn(InterpreterCode** code, pc_t* pc, pc_t* limit, WasmVal val) { |
| 1160 return static_cast<int>(code->targets->Lookup(pc)); | |
| 1161 } | |
| 1162 | |
| 1163 int DoBreak(InterpreterCode* code, pc_t pc, size_t depth) { | |
| 1164 size_t bp = blocks_.size() - depth - 1; | |
| 1165 Block* target = &blocks_[bp]; | |
| 1166 DoStackTransfer(target->sp, target->arity); | |
| 1167 blocks_.resize(bp); | |
| 1168 return LookupTarget(code, pc); | |
| 1169 } | |
| 1170 | |
| 1171 bool DoReturn(InterpreterCode** code, pc_t* pc, pc_t* limit, size_t arity) { | |
| 1172 DCHECK_GT(frames_.size(), 0u); | 1178 DCHECK_GT(frames_.size(), 0u); |
| 1173 // Pop all blocks for this frame. | 1179 stack_.resize(frames_.back().sp); |
| 1174 while (!blocks_.empty() && blocks_.back().fp == frames_.size()) { | |
| 1175 blocks_.pop_back(); | |
| 1176 } | |
| 1177 | |
| 1178 sp_t dest = frames_.back().sp; | |
| 1179 frames_.pop_back(); | 1180 frames_.pop_back(); |
| 1180 if (frames_.size() == 0) { | 1181 if (frames_.size() == 0) { |
| 1181 // A return from the last frame terminates the execution. | 1182 // A return from the top frame terminates the execution. |
| 1182 state_ = WasmInterpreter::FINISHED; | 1183 state_ = WasmInterpreter::FINISHED; |
| 1183 DoStackTransfer(0, arity); | 1184 stack_.clear(); |
| 1185 stack_.push_back(val); |
| 1184 TRACE(" => finish\n"); | 1186 TRACE(" => finish\n"); |
| 1185 return false; | 1187 return false; |
| 1186 } else { | 1188 } else { |
| 1187 // Return to caller frame. | 1189 // Return to caller frame. |
| 1188 Frame* top = &frames_.back(); | 1190 Frame* top = &frames_.back(); |
| 1189 *code = top->code; | 1191 *code = top->code; |
| 1190 *pc = top->ret_pc; | 1192 *pc = top->ret_pc; |
| 1191 *limit = top->code->end - top->code->start; | 1193 *limit = top->code->end - top->code->start; |
| 1194 if (top->code->start[top->call_pc] == kExprCallIndirect || |
| 1195 (top->code->orig_start && |
| 1196 top->code->orig_start[top->call_pc] == kExprCallIndirect)) { |
| 1197 // UGLY: An indirect call has the additional function index on the |
| 1198 // stack. |
| 1199 stack_.pop_back(); |
| 1200 } |
| 1192 TRACE(" => pop func#%u @%zu\n", (*code)->function->func_index, *pc); | 1201 TRACE(" => pop func#%u @%zu\n", (*code)->function->func_index, *pc); |
| 1193 DoStackTransfer(dest, arity); | 1202 |
| 1203 stack_.push_back(val); |
| 1194 return true; | 1204 return true; |
| 1195 } | 1205 } |
| 1196 } | 1206 } |
| 1197 | 1207 |
| 1198 void DoCall(InterpreterCode* target, pc_t* pc, pc_t ret_pc, pc_t* limit) { | 1208 void DoCall(InterpreterCode* target, pc_t* pc, pc_t ret_pc, pc_t* limit) { |
| 1199 PushFrame(target, *pc, ret_pc); | 1209 PushFrame(target, *pc, ret_pc); |
| 1200 *pc = frames_.back().ret_pc; | 1210 *pc = frames_.back().ret_pc; |
| 1201 *limit = target->end - target->start; | 1211 *limit = target->end - target->start; |
| 1202 } | 1212 } |
| 1203 | 1213 |
| 1204 // Copies {arity} values on the top of the stack down the stack to {dest}, | 1214 // Adjust the program counter {pc} and the stack contents according to the |
| 1205 // dropping the values in-between. | 1215 // code's precomputed control transfer map. Returns the different between |
| 1206 void DoStackTransfer(sp_t dest, size_t arity) { | 1216 // the new pc and the old pc. |
| 1207 // before: |---------------| pop_count | arity | | 1217 int DoControlTransfer(InterpreterCode* code, pc_t pc) { |
| 1208 // ^ 0 ^ dest ^ stack_.size() | 1218 auto target = code->targets->Lookup(pc); |
| 1209 // | 1219 switch (target.action) { |
| 1210 // after: |---------------| arity | | 1220 case ControlTransfer::kNoAction: |
| 1211 // ^ 0 ^ stack_.size() | 1221 TRACE(" action [sp-%u]\n", target.spdiff); |
| 1212 DCHECK_LE(dest, stack_.size()); | 1222 PopN(target.spdiff); |
| 1213 DCHECK_LE(dest + arity, stack_.size()); | 1223 break; |
| 1214 size_t pop_count = stack_.size() - dest - arity; | 1224 case ControlTransfer::kPopAndRepush: { |
| 1215 for (size_t i = 0; i < arity; i++) { | 1225 WasmVal val = Pop(); |
| 1216 stack_[dest + i] = stack_[dest + pop_count + i]; | 1226 TRACE(" action [pop x, sp-%u, push x]\n", target.spdiff - 1); |
| 1227 DCHECK_GE(target.spdiff, 1u); |
| 1228 PopN(target.spdiff - 1); |
| 1229 Push(pc, val); |
| 1230 break; |
| 1231 } |
| 1232 case ControlTransfer::kPushVoid: |
| 1233 TRACE(" action [sp-%u, push void]\n", target.spdiff); |
| 1234 PopN(target.spdiff); |
| 1235 Push(pc, WasmVal()); |
| 1236 break; |
| 1217 } | 1237 } |
| 1218 stack_.resize(stack_.size() - pop_count); | 1238 return target.pcdiff; |
| 1219 } | 1239 } |
| 1220 | 1240 |
| 1221 void Execute(InterpreterCode* code, pc_t pc, int max) { | 1241 void Execute(InterpreterCode* code, pc_t pc, int max) { |
| 1222 Decoder decoder(code->start, code->end); | 1242 Decoder decoder(code->start, code->end); |
| 1223 pc_t limit = code->end - code->start; | 1243 pc_t limit = code->end - code->start; |
| 1224 while (true) { | 1244 while (true) { |
| 1225 if (max-- <= 0) { | 1245 if (max-- <= 0) { |
| 1226 // Maximum number of instructions reached. | 1246 // Maximum number of instructions reached. |
| 1227 state_ = WasmInterpreter::PAUSED; | 1247 state_ = WasmInterpreter::PAUSED; |
| 1228 return CommitPc(pc); | 1248 return CommitPc(pc); |
| 1229 } | 1249 } |
| 1230 | 1250 |
| 1231 if (pc >= limit) { | 1251 if (pc >= limit) { |
| 1232 // Fell off end of code; do an implicit return. | 1252 // Fell off end of code; do an implicit return. |
| 1233 TRACE("@%-3zu: ImplicitReturn\n", pc); | 1253 TRACE("@%-3zu: ImplicitReturn\n", pc); |
| 1234 if (!DoReturn(&code, &pc, &limit, code->function->sig->return_count())) | 1254 WasmVal val = PopArity(code->function->sig->return_count()); |
| 1235 return; | 1255 if (!DoReturn(&code, &pc, &limit, val)) return; |
| 1236 decoder.Reset(code->start, code->end); | 1256 decoder.Reset(code->start, code->end); |
| 1237 continue; | 1257 continue; |
| 1238 } | 1258 } |
| 1239 | 1259 |
| 1240 const char* skip = " "; | 1260 const char* skip = " "; |
| 1241 int len = 1; | 1261 int len = 1; |
| 1242 byte opcode = code->start[pc]; | 1262 byte opcode = code->start[pc]; |
| 1243 byte orig = opcode; | 1263 byte orig = opcode; |
| 1244 if (opcode == kInternalBreakpoint) { | 1264 if (opcode == kInternalBreakpoint) { |
| 1245 orig = code->orig_start[pc]; | 1265 orig = code->orig_start[pc]; |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1258 } | 1278 } |
| 1259 | 1279 |
| 1260 USE(skip); | 1280 USE(skip); |
| 1261 TRACE("@%-3zu: %s%-24s:", pc, skip, | 1281 TRACE("@%-3zu: %s%-24s:", pc, skip, |
| 1262 WasmOpcodes::OpcodeName(static_cast<WasmOpcode>(orig))); | 1282 WasmOpcodes::OpcodeName(static_cast<WasmOpcode>(orig))); |
| 1263 TraceValueStack(); | 1283 TraceValueStack(); |
| 1264 TRACE("\n"); | 1284 TRACE("\n"); |
| 1265 | 1285 |
| 1266 switch (orig) { | 1286 switch (orig) { |
| 1267 case kExprNop: | 1287 case kExprNop: |
| 1288 Push(pc, WasmVal()); |
| 1268 break; | 1289 break; |
| 1269 case kExprBlock: { | 1290 case kExprBlock: |
| 1270 BlockTypeOperand operand(&decoder, code->at(pc)); | |
| 1271 blocks_.push_back({pc, stack_.size(), frames_.size(), operand.arity}); | |
| 1272 len = 1 + operand.length; | |
| 1273 break; | |
| 1274 } | |
| 1275 case kExprLoop: { | 1291 case kExprLoop: { |
| 1276 BlockTypeOperand operand(&decoder, code->at(pc)); | 1292 // Do nothing. |
| 1277 blocks_.push_back({pc, stack_.size(), frames_.size(), 0}); | |
| 1278 len = 1 + operand.length; | |
| 1279 break; | 1293 break; |
| 1280 } | 1294 } |
| 1281 case kExprIf: { | 1295 case kExprIf: { |
| 1282 BlockTypeOperand operand(&decoder, code->at(pc)); | |
| 1283 WasmVal cond = Pop(); | 1296 WasmVal cond = Pop(); |
| 1284 bool is_true = cond.to<uint32_t>() != 0; | 1297 bool is_true = cond.to<uint32_t>() != 0; |
| 1285 blocks_.push_back({pc, stack_.size(), frames_.size(), operand.arity}); | |
| 1286 if (is_true) { | 1298 if (is_true) { |
| 1287 // fall through to the true block. | 1299 // fall through to the true block. |
| 1288 len = 1 + operand.length; | |
| 1289 TRACE(" true => fallthrough\n"); | 1300 TRACE(" true => fallthrough\n"); |
| 1290 } else { | 1301 } else { |
| 1291 len = LookupTarget(code, pc); | 1302 len = DoControlTransfer(code, pc); |
| 1292 TRACE(" false => @%zu\n", pc + len); | 1303 TRACE(" false => @%zu\n", pc + len); |
| 1293 } | 1304 } |
| 1294 break; | 1305 break; |
| 1295 } | 1306 } |
| 1296 case kExprElse: { | 1307 case kExprElse: { |
| 1297 blocks_.pop_back(); | 1308 len = DoControlTransfer(code, pc); |
| 1298 len = LookupTarget(code, pc); | |
| 1299 TRACE(" end => @%zu\n", pc + len); | 1309 TRACE(" end => @%zu\n", pc + len); |
| 1300 break; | 1310 break; |
| 1301 } | 1311 } |
| 1302 case kExprSelect: { | 1312 case kExprSelect: { |
| 1303 WasmVal cond = Pop(); | 1313 WasmVal cond = Pop(); |
| 1304 WasmVal fval = Pop(); | 1314 WasmVal fval = Pop(); |
| 1305 WasmVal tval = Pop(); | 1315 WasmVal tval = Pop(); |
| 1306 Push(pc, cond.to<int32_t>() != 0 ? tval : fval); | 1316 Push(pc, cond.to<int32_t>() != 0 ? tval : fval); |
| 1307 break; | 1317 break; |
| 1308 } | 1318 } |
| 1309 case kExprBr: { | 1319 case kExprBr: { |
| 1310 BreakDepthOperand operand(&decoder, code->at(pc)); | 1320 BreakDepthOperand operand(&decoder, code->at(pc)); |
| 1311 len = DoBreak(code, pc, operand.depth); | 1321 WasmVal val = PopArity(operand.arity); |
| 1322 len = DoControlTransfer(code, pc); |
| 1312 TRACE(" br => @%zu\n", pc + len); | 1323 TRACE(" br => @%zu\n", pc + len); |
| 1324 if (operand.arity > 0) Push(pc, val); |
| 1313 break; | 1325 break; |
| 1314 } | 1326 } |
| 1315 case kExprBrIf: { | 1327 case kExprBrIf: { |
| 1316 BreakDepthOperand operand(&decoder, code->at(pc)); | 1328 BreakDepthOperand operand(&decoder, code->at(pc)); |
| 1317 WasmVal cond = Pop(); | 1329 WasmVal cond = Pop(); |
| 1330 WasmVal val = PopArity(operand.arity); |
| 1318 bool is_true = cond.to<uint32_t>() != 0; | 1331 bool is_true = cond.to<uint32_t>() != 0; |
| 1319 if (is_true) { | 1332 if (is_true) { |
| 1320 len = DoBreak(code, pc, operand.depth); | 1333 len = DoControlTransfer(code, pc); |
| 1321 TRACE(" br_if => @%zu\n", pc + len); | 1334 TRACE(" br_if => @%zu\n", pc + len); |
| 1335 if (operand.arity > 0) Push(pc, val); |
| 1322 } else { | 1336 } else { |
| 1323 TRACE(" false => fallthrough\n"); | 1337 TRACE(" false => fallthrough\n"); |
| 1324 len = 1 + operand.length; | 1338 len = 1 + operand.length; |
| 1339 Push(pc, WasmVal()); |
| 1325 } | 1340 } |
| 1326 break; | 1341 break; |
| 1327 } | 1342 } |
| 1328 case kExprBrTable: { | 1343 case kExprBrTable: { |
| 1329 BranchTableOperand operand(&decoder, code->at(pc)); | 1344 BranchTableOperand operand(&decoder, code->at(pc)); |
| 1330 uint32_t key = Pop().to<uint32_t>(); | 1345 uint32_t key = Pop().to<uint32_t>(); |
| 1346 WasmVal val = PopArity(operand.arity); |
| 1331 if (key >= operand.table_count) key = operand.table_count; | 1347 if (key >= operand.table_count) key = operand.table_count; |
| 1332 len = key + DoBreak(code, pc + key, operand.table[key]); | 1348 len = DoControlTransfer(code, pc + key) + key; |
| 1333 TRACE(" br[%u] => @%zu\n", key, pc + key + len); | 1349 TRACE(" br[%u] => @%zu\n", key, pc + len); |
| 1350 if (operand.arity > 0) Push(pc, val); |
| 1334 break; | 1351 break; |
| 1335 } | 1352 } |
| 1336 case kExprReturn: { | 1353 case kExprReturn: { |
| 1337 size_t arity = code->function->sig->return_count(); | 1354 ReturnArityOperand operand(&decoder, code->at(pc)); |
| 1338 if (!DoReturn(&code, &pc, &limit, arity)) return; | 1355 WasmVal val = PopArity(operand.arity); |
| 1356 if (!DoReturn(&code, &pc, &limit, val)) return; |
| 1339 decoder.Reset(code->start, code->end); | 1357 decoder.Reset(code->start, code->end); |
| 1340 continue; | 1358 continue; |
| 1341 } | 1359 } |
| 1342 case kExprUnreachable: { | 1360 case kExprUnreachable: { |
| 1343 DoTrap(kTrapUnreachable, pc); | 1361 DoTrap(kTrapUnreachable, pc); |
| 1344 return CommitPc(pc); | 1362 return CommitPc(pc); |
| 1345 } | 1363 } |
| 1346 case kExprEnd: { | 1364 case kExprEnd: { |
| 1347 blocks_.pop_back(); | 1365 len = DoControlTransfer(code, pc); |
| 1366 DCHECK_EQ(1, len); |
| 1348 break; | 1367 break; |
| 1349 } | 1368 } |
| 1350 case kExprI8Const: { | 1369 case kExprI8Const: { |
| 1351 ImmI8Operand operand(&decoder, code->at(pc)); | 1370 ImmI8Operand operand(&decoder, code->at(pc)); |
| 1352 Push(pc, WasmVal(operand.value)); | 1371 Push(pc, WasmVal(operand.value)); |
| 1353 len = 1 + operand.length; | 1372 len = 1 + operand.length; |
| 1354 break; | 1373 break; |
| 1355 } | 1374 } |
| 1356 case kExprI32Const: { | 1375 case kExprI32Const: { |
| 1357 ImmI32Operand operand(&decoder, code->at(pc)); | 1376 ImmI32Operand operand(&decoder, code->at(pc)); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 1380 case kExprGetLocal: { | 1399 case kExprGetLocal: { |
| 1381 LocalIndexOperand operand(&decoder, code->at(pc)); | 1400 LocalIndexOperand operand(&decoder, code->at(pc)); |
| 1382 Push(pc, stack_[frames_.back().sp + operand.index]); | 1401 Push(pc, stack_[frames_.back().sp + operand.index]); |
| 1383 len = 1 + operand.length; | 1402 len = 1 + operand.length; |
| 1384 break; | 1403 break; |
| 1385 } | 1404 } |
| 1386 case kExprSetLocal: { | 1405 case kExprSetLocal: { |
| 1387 LocalIndexOperand operand(&decoder, code->at(pc)); | 1406 LocalIndexOperand operand(&decoder, code->at(pc)); |
| 1388 WasmVal val = Pop(); | 1407 WasmVal val = Pop(); |
| 1389 stack_[frames_.back().sp + operand.index] = val; | 1408 stack_[frames_.back().sp + operand.index] = val; |
| 1390 len = 1 + operand.length; | |
| 1391 break; | |
| 1392 } | |
| 1393 case kExprTeeLocal: { | |
| 1394 LocalIndexOperand operand(&decoder, code->at(pc)); | |
| 1395 WasmVal val = Pop(); | |
| 1396 stack_[frames_.back().sp + operand.index] = val; | |
| 1397 Push(pc, val); | 1409 Push(pc, val); |
| 1398 len = 1 + operand.length; | 1410 len = 1 + operand.length; |
| 1399 break; | 1411 break; |
| 1400 } | 1412 } |
| 1401 case kExprDrop: { | |
| 1402 Pop(); | |
| 1403 break; | |
| 1404 } | |
| 1405 case kExprCallFunction: { | 1413 case kExprCallFunction: { |
| 1406 CallFunctionOperand operand(&decoder, code->at(pc)); | 1414 CallFunctionOperand operand(&decoder, code->at(pc)); |
| 1407 InterpreterCode* target = codemap()->GetCode(operand.index); | 1415 InterpreterCode* target = codemap()->GetCode(operand.index); |
| 1408 DoCall(target, &pc, pc + 1 + operand.length, &limit); | 1416 DoCall(target, &pc, pc + 1 + operand.length, &limit); |
| 1409 code = target; | 1417 code = target; |
| 1410 decoder.Reset(code->start, code->end); | 1418 decoder.Reset(code->start, code->end); |
| 1411 continue; | 1419 continue; |
| 1412 } | 1420 } |
| 1413 case kExprCallIndirect: { | 1421 case kExprCallIndirect: { |
| 1414 CallIndirectOperand operand(&decoder, code->at(pc)); | 1422 CallIndirectOperand operand(&decoder, code->at(pc)); |
| 1415 uint32_t entry_index = Pop().to<uint32_t>(); | 1423 size_t index = stack_.size() - operand.arity - 1; |
| 1424 DCHECK_LT(index, stack_.size()); |
| 1425 uint32_t entry_index = stack_[index].to<uint32_t>(); |
| 1416 // Assume only one table for now. | 1426 // Assume only one table for now. |
| 1417 DCHECK_LE(module()->function_tables.size(), 1u); | 1427 DCHECK_LE(module()->function_tables.size(), 1u); |
| 1418 InterpreterCode* target = codemap()->GetIndirectCode(0, entry_index); | 1428 InterpreterCode* target = codemap()->GetIndirectCode(0, entry_index); |
| 1419 if (target == nullptr) { | 1429 if (target == nullptr) { |
| 1420 return DoTrap(kTrapFuncInvalid, pc); | 1430 return DoTrap(kTrapFuncInvalid, pc); |
| 1421 } else if (target->function->sig_index != operand.index) { | 1431 } else if (target->function->sig_index != operand.index) { |
| 1422 return DoTrap(kTrapFuncSigMismatch, pc); | 1432 return DoTrap(kTrapFuncSigMismatch, pc); |
| 1423 } | 1433 } |
| 1424 | 1434 |
| 1425 DoCall(target, &pc, pc + 1 + operand.length, &limit); | 1435 DoCall(target, &pc, pc + 1 + operand.length, &limit); |
| 1426 code = target; | 1436 code = target; |
| 1427 decoder.Reset(code->start, code->end); | 1437 decoder.Reset(code->start, code->end); |
| 1428 continue; | 1438 continue; |
| 1429 } | 1439 } |
| 1440 case kExprCallImport: { |
| 1441 UNIMPLEMENTED(); |
| 1442 break; |
| 1443 } |
| 1430 case kExprGetGlobal: { | 1444 case kExprGetGlobal: { |
| 1431 GlobalIndexOperand operand(&decoder, code->at(pc)); | 1445 GlobalIndexOperand operand(&decoder, code->at(pc)); |
| 1432 const WasmGlobal* global = &module()->globals[operand.index]; | 1446 const WasmGlobal* global = &module()->globals[operand.index]; |
| 1433 byte* ptr = instance()->globals_start + global->offset; | 1447 byte* ptr = instance()->globals_start + global->offset; |
| 1434 LocalType type = global->type; | 1448 LocalType type = global->type; |
| 1435 WasmVal val; | 1449 WasmVal val; |
| 1436 if (type == kAstI32) { | 1450 if (type == kAstI32) { |
| 1437 val = WasmVal(*reinterpret_cast<int32_t*>(ptr)); | 1451 val = WasmVal(*reinterpret_cast<int32_t*>(ptr)); |
| 1438 } else if (type == kAstI64) { | 1452 } else if (type == kAstI64) { |
| 1439 val = WasmVal(*reinterpret_cast<int64_t*>(ptr)); | 1453 val = WasmVal(*reinterpret_cast<int64_t*>(ptr)); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1458 *reinterpret_cast<int32_t*>(ptr) = val.to<int32_t>(); | 1472 *reinterpret_cast<int32_t*>(ptr) = val.to<int32_t>(); |
| 1459 } else if (type == kAstI64) { | 1473 } else if (type == kAstI64) { |
| 1460 *reinterpret_cast<int64_t*>(ptr) = val.to<int64_t>(); | 1474 *reinterpret_cast<int64_t*>(ptr) = val.to<int64_t>(); |
| 1461 } else if (type == kAstF32) { | 1475 } else if (type == kAstF32) { |
| 1462 *reinterpret_cast<float*>(ptr) = val.to<float>(); | 1476 *reinterpret_cast<float*>(ptr) = val.to<float>(); |
| 1463 } else if (type == kAstF64) { | 1477 } else if (type == kAstF64) { |
| 1464 *reinterpret_cast<double*>(ptr) = val.to<double>(); | 1478 *reinterpret_cast<double*>(ptr) = val.to<double>(); |
| 1465 } else { | 1479 } else { |
| 1466 UNREACHABLE(); | 1480 UNREACHABLE(); |
| 1467 } | 1481 } |
| 1482 Push(pc, val); |
| 1468 len = 1 + operand.length; | 1483 len = 1 + operand.length; |
| 1469 break; | 1484 break; |
| 1470 } | 1485 } |
| 1471 | 1486 |
| 1472 #define LOAD_CASE(name, ctype, mtype) \ | 1487 #define LOAD_CASE(name, ctype, mtype) \ |
| 1473 case kExpr##name: { \ | 1488 case kExpr##name: { \ |
| 1474 MemoryAccessOperand operand(&decoder, code->at(pc), sizeof(ctype)); \ | 1489 MemoryAccessOperand operand(&decoder, code->at(pc), sizeof(ctype)); \ |
| 1475 uint32_t index = Pop().to<uint32_t>(); \ | 1490 uint32_t index = Pop().to<uint32_t>(); \ |
| 1476 size_t effective_mem_size = instance()->mem_size - sizeof(mtype); \ | 1491 size_t effective_mem_size = instance()->mem_size - sizeof(mtype); \ |
| 1477 if (operand.offset > effective_mem_size || \ | 1492 if (operand.offset > effective_mem_size || \ |
| (...skipping 28 matching lines...) Expand all Loading... |
| 1506 MemoryAccessOperand operand(&decoder, code->at(pc), sizeof(ctype)); \ | 1521 MemoryAccessOperand operand(&decoder, code->at(pc), sizeof(ctype)); \ |
| 1507 WasmVal val = Pop(); \ | 1522 WasmVal val = Pop(); \ |
| 1508 uint32_t index = Pop().to<uint32_t>(); \ | 1523 uint32_t index = Pop().to<uint32_t>(); \ |
| 1509 size_t effective_mem_size = instance()->mem_size - sizeof(mtype); \ | 1524 size_t effective_mem_size = instance()->mem_size - sizeof(mtype); \ |
| 1510 if (operand.offset > effective_mem_size || \ | 1525 if (operand.offset > effective_mem_size || \ |
| 1511 index > (effective_mem_size - operand.offset)) { \ | 1526 index > (effective_mem_size - operand.offset)) { \ |
| 1512 return DoTrap(kTrapMemOutOfBounds, pc); \ | 1527 return DoTrap(kTrapMemOutOfBounds, pc); \ |
| 1513 } \ | 1528 } \ |
| 1514 byte* addr = instance()->mem_start + operand.offset + index; \ | 1529 byte* addr = instance()->mem_start + operand.offset + index; \ |
| 1515 WriteLittleEndianValue<mtype>(addr, static_cast<mtype>(val.to<ctype>())); \ | 1530 WriteLittleEndianValue<mtype>(addr, static_cast<mtype>(val.to<ctype>())); \ |
| 1531 Push(pc, val); \ |
| 1516 len = 1 + operand.length; \ | 1532 len = 1 + operand.length; \ |
| 1517 break; \ | 1533 break; \ |
| 1518 } | 1534 } |
| 1519 | 1535 |
| 1520 STORE_CASE(I32StoreMem8, int32_t, int8_t); | 1536 STORE_CASE(I32StoreMem8, int32_t, int8_t); |
| 1521 STORE_CASE(I32StoreMem16, int32_t, int16_t); | 1537 STORE_CASE(I32StoreMem16, int32_t, int16_t); |
| 1522 STORE_CASE(I64StoreMem8, int64_t, int8_t); | 1538 STORE_CASE(I64StoreMem8, int64_t, int8_t); |
| 1523 STORE_CASE(I64StoreMem16, int64_t, int16_t); | 1539 STORE_CASE(I64StoreMem16, int64_t, int16_t); |
| 1524 STORE_CASE(I64StoreMem32, int64_t, int32_t); | 1540 STORE_CASE(I64StoreMem32, int64_t, int32_t); |
| 1525 STORE_CASE(I32StoreMem, int32_t, int32_t); | 1541 STORE_CASE(I32StoreMem, int32_t, int32_t); |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1571 ASMJS_STORE_CASE(I32AsmjsStoreMem, int32_t, int32_t); | 1587 ASMJS_STORE_CASE(I32AsmjsStoreMem, int32_t, int32_t); |
| 1572 ASMJS_STORE_CASE(F32AsmjsStoreMem, float, float); | 1588 ASMJS_STORE_CASE(F32AsmjsStoreMem, float, float); |
| 1573 ASMJS_STORE_CASE(F64AsmjsStoreMem, double, double); | 1589 ASMJS_STORE_CASE(F64AsmjsStoreMem, double, double); |
| 1574 #undef ASMJS_STORE_CASE | 1590 #undef ASMJS_STORE_CASE |
| 1575 case kExprGrowMemory: { | 1591 case kExprGrowMemory: { |
| 1576 uint32_t delta_pages = Pop().to<uint32_t>(); | 1592 uint32_t delta_pages = Pop().to<uint32_t>(); |
| 1577 Push(pc, WasmVal(ExecuteGrowMemory(delta_pages, instance()))); | 1593 Push(pc, WasmVal(ExecuteGrowMemory(delta_pages, instance()))); |
| 1578 break; | 1594 break; |
| 1579 } | 1595 } |
| 1580 case kExprMemorySize: { | 1596 case kExprMemorySize: { |
| 1581 Push(pc, WasmVal(static_cast<uint32_t>(instance()->mem_size / | 1597 Push(pc, WasmVal(static_cast<uint32_t>(instance()->mem_size))); |
| 1582 WasmModule::kPageSize))); | |
| 1583 break; | 1598 break; |
| 1584 } | 1599 } |
| 1585 #define EXECUTE_SIMPLE_BINOP(name, ctype, op) \ | 1600 #define EXECUTE_SIMPLE_BINOP(name, ctype, op) \ |
| 1586 case kExpr##name: { \ | 1601 case kExpr##name: { \ |
| 1587 WasmVal rval = Pop(); \ | 1602 WasmVal rval = Pop(); \ |
| 1588 WasmVal lval = Pop(); \ | 1603 WasmVal lval = Pop(); \ |
| 1589 WasmVal result(lval.to<ctype>() op rval.to<ctype>()); \ | 1604 WasmVal result(lval.to<ctype>() op rval.to<ctype>()); \ |
| 1590 Push(pc, result); \ | 1605 Push(pc, result); \ |
| 1591 break; \ | 1606 break; \ |
| 1592 } | 1607 } |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1647 } | 1662 } |
| 1648 | 1663 |
| 1649 WasmVal PopArity(size_t arity) { | 1664 WasmVal PopArity(size_t arity) { |
| 1650 if (arity == 0) return WasmVal(); | 1665 if (arity == 0) return WasmVal(); |
| 1651 CHECK_EQ(1, arity); | 1666 CHECK_EQ(1, arity); |
| 1652 return Pop(); | 1667 return Pop(); |
| 1653 } | 1668 } |
| 1654 | 1669 |
| 1655 void Push(pc_t pc, WasmVal val) { | 1670 void Push(pc_t pc, WasmVal val) { |
| 1656 // TODO(titzer): store PC as well? | 1671 // TODO(titzer): store PC as well? |
| 1657 if (val.type != kAstStmt) stack_.push_back(val); | 1672 stack_.push_back(val); |
| 1658 } | 1673 } |
| 1659 | 1674 |
| 1660 void TraceStack(const char* phase, pc_t pc) { | 1675 void TraceStack(const char* phase, pc_t pc) { |
| 1661 if (FLAG_trace_wasm_interpreter) { | 1676 if (FLAG_trace_wasm_interpreter) { |
| 1662 PrintF("%s @%zu", phase, pc); | 1677 PrintF("%s @%zu", phase, pc); |
| 1663 UNIMPLEMENTED(); | 1678 UNIMPLEMENTED(); |
| 1664 PrintF("\n"); | 1679 PrintF("\n"); |
| 1665 } | 1680 } |
| 1666 } | 1681 } |
| 1667 | 1682 |
| (...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1828 } | 1843 } |
| 1829 | 1844 |
| 1830 bool WasmInterpreter::SetFunctionCodeForTesting(const WasmFunction* function, | 1845 bool WasmInterpreter::SetFunctionCodeForTesting(const WasmFunction* function, |
| 1831 const byte* start, | 1846 const byte* start, |
| 1832 const byte* end) { | 1847 const byte* end) { |
| 1833 return internals_->codemap_.SetFunctionCode(function, start, end); | 1848 return internals_->codemap_.SetFunctionCode(function, start, end); |
| 1834 } | 1849 } |
| 1835 | 1850 |
| 1836 ControlTransferMap WasmInterpreter::ComputeControlTransfersForTesting( | 1851 ControlTransferMap WasmInterpreter::ComputeControlTransfersForTesting( |
| 1837 Zone* zone, const byte* start, const byte* end) { | 1852 Zone* zone, const byte* start, const byte* end) { |
| 1838 ControlTransfers targets(zone, nullptr, nullptr, start, end); | 1853 ControlTransfers targets(zone, 0, start, end); |
| 1839 return targets.map_; | 1854 return targets.map_; |
| 1840 } | 1855 } |
| 1841 | 1856 |
| 1842 } // namespace wasm | 1857 } // namespace wasm |
| 1843 } // namespace internal | 1858 } // namespace internal |
| 1844 } // namespace v8 | 1859 } // namespace v8 |
| OLD | NEW |