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