Where Online Learning is simpler!
The C and C++ Include Header Files
cat -n /usr/include/wabt/interp/interp.h
1 /* 2 * Copyright 2020 WebAssembly Community Group participants 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef WABT_INTERP_H_ 18 #define WABT_INTERP_H_ 19 20 #include <cstdint> 21 #include <functional> 22 #include <memory> 23 #include <set> 24 #include <string> 25 #include <string_view> 26 #include <type_traits> 27 #include <vector> 28 29 #include "wabt/cast.h" 30 #include "wabt/config.h" 31 #include "wabt/common.h" 32 #include "wabt/feature.h" 33 #include "wabt/opcode.h" 34 #include "wabt/result.h" 35 36 #include "wabt/interp/istream.h" 37 38 namespace wabt { 39 namespace interp { 40 41 class Store; 42 class Object; 43 class Trap; 44 class DataSegment; 45 class ElemSegment; 46 class Module; 47 class Instance; 48 class Thread; 49 template <typename T> 50 class RefPtr; 51 52 using s8 = int8_t; 53 using u8 = uint8_t; 54 using s16 = int16_t; 55 using u16 = uint16_t; 56 using s32 = int32_t; 57 using u32 = uint32_t; 58 using Index = uint32_t; 59 using s64 = int64_t; 60 using u64 = uint64_t; 61 using f32 = float; 62 using f64 = double; 63 64 using Buffer = std::vector<u8>; 65 66 using ValueType = wabt::Type; 67 using ValueTypes = std::vector<ValueType>; 68 69 template <typename T> 70 bool HasType(ValueType); 71 template <typename T> 72 void RequireType(ValueType); 73 bool IsReference(ValueType); 74 bool TypesMatch(ValueType expected, ValueType actual); 75 76 using ExternKind = ExternalKind; 77 enum class Mutability { Const, Var }; 78 enum class TagAttr { Exception }; 79 using SegmentMode = SegmentKind; 80 81 enum class ObjectKind { 82 Null, 83 Foreign, 84 Trap, 85 Exception, 86 DefinedFunc, 87 HostFunc, 88 Table, 89 Memory, 90 Global, 91 Tag, 92 Module, 93 Instance, 94 95 First = Null, 96 Last = Instance, 97 }; 98 99 constexpr int kCommandTypeCount = WABT_ENUM_COUNT(ObjectKind); 100 101 const char* GetName(Mutability); 102 const std::string GetName(ValueType); 103 const char* GetName(ExternKind); 104 const char* GetName(ObjectKind); 105 106 struct Ref { 107 static const Ref Null; 108 109 Ref() = default; 110 explicit Ref(size_t index); 111 112 friend bool operator==(Ref, Ref); 113 friend bool operator!=(Ref, Ref); 114 115 size_t index; 116 }; 117 using RefVec = std::vector<Ref>; 118 119 template <typename T, u8 L> 120 struct Simd { 121 using LaneType = T; 122 static constexpr u8 lanes = L; 123 124 T v[L]; 125 126 inline T& operator[](u8 idx) { 127 #if WABT_BIG_ENDIAN 128 idx = (~idx) & (L - 1); 129 #endif 130 return v[idx]; 131 } 132 inline T operator[](u8 idx) const { 133 #if WABT_BIG_ENDIAN 134 idx = (~idx) & (L - 1); 135 #endif 136 return v[idx]; 137 } 138 }; 139 using s8x16 = Simd<s8, 16>; 140 using u8x16 = Simd<u8, 16>; 141 using s16x8 = Simd<s16, 8>; 142 using u16x8 = Simd<u16, 8>; 143 using s32x4 = Simd<s32, 4>; 144 using u32x4 = Simd<u32, 4>; 145 using s64x2 = Simd<s64, 2>; 146 using u64x2 = Simd<u64, 2>; 147 using f32x4 = Simd<f32, 4>; 148 using f64x2 = Simd<f64, 2>; 149 150 // Used for load extend instructions. 151 using s8x8 = Simd<s8, 8>; 152 using u8x8 = Simd<u8, 8>; 153 using s16x4 = Simd<s16, 4>; 154 using u16x4 = Simd<u16, 4>; 155 using s32x2 = Simd<s32, 2>; 156 using u32x2 = Simd<u32, 2>; 157 158 //// Types //// 159 160 bool CanGrow(const Limits&, u32 old_size, u32 delta, u32* new_size); 161 Result Match(const Limits& expected, 162 const Limits& actual, 163 std::string* out_msg); 164 165 struct ExternType { 166 explicit ExternType(ExternKind); 167 virtual ~ExternType() {} 168 virtual std::unique_ptr<ExternType> Clone() const = 0; 169 170 ExternKind kind; 171 }; 172 173 struct FuncType : ExternType { 174 static const ExternKind skind = ExternKind::Func; 175 static bool classof(const ExternType* type); 176 177 explicit FuncType(ValueTypes params, ValueTypes results); 178 179 std::unique_ptr<ExternType> Clone() const override; 180 181 friend Result Match(const FuncType& expected, 182 const FuncType& actual, 183 std::string* out_msg); 184 185 ValueTypes params; 186 ValueTypes results; 187 }; 188 189 struct TableType : ExternType { 190 static const ExternKind skind = ExternKind::Table; 191 static bool classof(const ExternType* type); 192 193 explicit TableType(ValueType, Limits); 194 195 std::unique_ptr<ExternType> Clone() const override; 196 197 friend Result Match(const TableType& expected, 198 const TableType& actual, 199 std::string* out_msg); 200 201 ValueType element; 202 Limits limits; 203 }; 204 205 struct MemoryType : ExternType { 206 static const ExternKind skind = ExternKind::Memory; 207 static bool classof(const ExternType* type); 208 209 explicit MemoryType(Limits); 210 211 std::unique_ptr<ExternType> Clone() const override; 212 213 friend Result Match(const MemoryType& expected, 214 const MemoryType& actual, 215 std::string* out_msg); 216 217 Limits limits; 218 }; 219 220 struct GlobalType : ExternType { 221 static const ExternKind skind = ExternKind::Global; 222 static bool classof(const ExternType* type); 223 224 explicit GlobalType(ValueType, Mutability); 225 226 std::unique_ptr<ExternType> Clone() const override; 227 228 friend Result Match(const GlobalType& expected, 229 const GlobalType& actual, 230 std::string* out_msg); 231 232 ValueType type; 233 Mutability mut; 234 }; 235 236 struct TagType : ExternType { 237 static const ExternKind skind = ExternKind::Tag; 238 static bool classof(const ExternType* type); 239 240 explicit TagType(TagAttr, const ValueTypes&); 241 242 std::unique_ptr<ExternType> Clone() const override; 243 244 friend Result Match(const TagType& expected, 245 const TagType& actual, 246 std::string* out_msg); 247 248 TagAttr attr; 249 ValueTypes signature; 250 }; 251 252 struct ImportType { 253 explicit ImportType(std::string module, 254 std::string name, 255 std::unique_ptr<ExternType>); 256 ImportType(const ImportType&); 257 ImportType& operator=(const ImportType&); 258 259 std::string module; 260 std::string name; 261 std::unique_ptr<ExternType> type; 262 }; 263 264 struct ExportType { 265 explicit ExportType(std::string name, std::unique_ptr<ExternType>); 266 ExportType(const ExportType&); 267 ExportType& operator=(const ExportType&); 268 269 std::string name; 270 std::unique_ptr<ExternType> type; 271 }; 272 273 //// Structure //// 274 275 struct ImportDesc { 276 ImportType type; 277 }; 278 279 struct LocalDesc { 280 ValueType type; 281 u32 count; 282 // One past the last local index that has this type. For example, a vector of 283 // LocalDesc might look like: 284 // 285 // {{I32, 2, 2}, {I64, 3, 5}, {F32, 1, 6}, ...} 286 // 287 // This makes it possible to use a binary search to find the type of a local 288 // at a given index. 289 u32 end; 290 }; 291 292 // Metadata for representing exception handlers associated with a function's 293 // code. This is needed to look up exceptions from call frames from interpreter 294 // instructions. 295 struct CatchDesc { 296 Index tag_index; 297 u32 offset; 298 }; 299 300 // Handlers for a catch-less `try` or `try-catch` block are included in the 301 // Catch kind. `try-delegate` instructions create a Delegate handler. 302 enum class HandlerKind { Catch, Delegate }; 303 304 struct HandlerDesc { 305 HandlerKind kind; 306 u32 try_start_offset; 307 u32 try_end_offset; 308 std::vector<CatchDesc> catches; 309 union { 310 u32 catch_all_offset; 311 u32 delegate_handler_index; 312 }; 313 // Local stack heights at the handler site that need to be restored. 314 u32 values; 315 u32 exceptions; 316 }; 317 318 struct FuncDesc { 319 // Includes params. 320 ValueType GetLocalType(Index) const; 321 322 FuncType type; 323 std::vector<LocalDesc> locals; 324 u32 code_offset; // Istream offset. 325 std::vector<HandlerDesc> handlers; 326 }; 327 328 struct TableDesc { 329 TableType type; 330 }; 331 332 struct MemoryDesc { 333 MemoryType type; 334 }; 335 336 struct GlobalDesc { 337 GlobalType type; 338 FuncDesc init_func; 339 }; 340 341 struct TagDesc { 342 TagType type; 343 }; 344 345 struct ExportDesc { 346 ExportType type; 347 Index index; 348 }; 349 350 struct StartDesc { 351 Index func_index; 352 }; 353 354 struct DataDesc { 355 Buffer data; 356 SegmentMode mode; 357 Index memory_index; 358 FuncDesc init_func; 359 }; 360 361 struct ElemDesc { 362 std::vector<FuncDesc> elements; 363 ValueType type; 364 SegmentMode mode; 365 Index table_index; 366 FuncDesc init_func; 367 }; 368 369 struct ModuleDesc { 370 std::vector<FuncType> func_types; 371 std::vector<ImportDesc> imports; 372 std::vector<FuncDesc> funcs; 373 std::vector<TableDesc> tables; 374 std::vector<MemoryDesc> memories; 375 std::vector<GlobalDesc> globals; 376 std::vector<TagDesc> tags; 377 std::vector<ExportDesc> exports; 378 std::vector<StartDesc> starts; 379 std::vector<ElemDesc> elems; 380 std::vector<DataDesc> datas; 381 Istream istream; 382 }; 383 384 //// Runtime //// 385 386 struct Frame { 387 explicit Frame(Ref func, 388 u32 values, 389 u32 exceptions, 390 u32 offset, 391 Instance*, 392 Module*); 393 394 void Mark(Store&); 395 396 Ref func; 397 u32 values; // Height of the value stack at this activation. 398 u32 exceptions; // Height of the exception stack at this activation. 399 u32 offset; // Istream offset; either the return PC, or the current PC. 400 401 // Cached for convenience. Both are null if func is a HostFunc. 402 Instance* inst; 403 Module* mod; 404 }; 405 406 template <typename T> 407 class FreeList { 408 public: 409 using Index = size_t; 410 411 ~FreeList(); 412 413 template <typename... Args> 414 Index New(Args&&...); 415 void Delete(Index); 416 417 bool IsUsed(Index) const; 418 419 const T& Get(Index) const; 420 T& Get(Index); 421 422 Index size() const; // 1 greater than the maximum index. 423 Index count() const; // The number of used elements. 424 425 private: 426 // As for Refs, the free bit is 0x80..0. This bit is never 427 // set for valid Refs, since it would mean more objects 428 // are allocated than the total amount of memory. 429 static const Index refFreeBit = (SIZE_MAX >> 1) + 1; 430 431 // As for Objects, the free bit is 0x1. This bit is never 432 // set for valid Objects, since pointers are aligned to at 433 // least four bytes. 434 static const Index ptrFreeBit = 1; 435 static const int ptrFreeShift = 1; 436 437 std::vector<T> list_; 438 // If free_head_ is zero, there is no free slots in list_, 439 // otherwise free_head_ - 1 represents the first free slot. 440 Index free_head_ = 0; 441 Index free_items_ = 0; 442 }; 443 444 class Store { 445 public: 446 using ObjectList = FreeList<Object*>; 447 using RootList = FreeList<Ref>; 448 449 explicit Store(const Features& = Features{}); 450 451 Store(const Store&) = delete; 452 Store& operator=(const Store&) = delete; 453 Store& operator=(const Store&&) = delete; 454 455 bool IsValid(Ref) const; 456 bool HasValueType(Ref, ValueType) const; 457 template <typename T> 458 bool Is(Ref) const; 459 460 template <typename T, typename... Args> 461 RefPtr<T> Alloc(Args&&...); 462 template <typename T> 463 Result Get(Ref, RefPtr<T>* out); 464 template <typename T> 465 RefPtr<T> UnsafeGet(Ref); 466 467 RootList::Index NewRoot(Ref); 468 RootList::Index CopyRoot(RootList::Index); 469 void DeleteRoot(RootList::Index); 470 471 void Collect(); 472 void Mark(Ref); 473 void Mark(const RefVec&); 474 475 ObjectList::Index object_count() const; 476 477 const Features& features() const; 478 void setFeatures(const Features& features) { features_ = features; } 479 480 std::set<Thread*>& threads(); 481 482 private: 483 template <typename T> 484 friend class RefPtr; 485 486 struct GCContext { 487 int call_depth = 0; 488 std::vector<bool> marks; 489 std::vector<size_t> untraced_objects; 490 }; 491 492 static const int max_call_depth = 10; 493 494 Features features_; 495 GCContext gc_context_; 496 // This set contains the currently active Thread objects. 497 std::set<Thread*> threads_; 498 ObjectList objects_; 499 RootList roots_; 500 }; 501 502 template <typename T> 503 class RefPtr { 504 public: 505 RefPtr(); 506 RefPtr(Store&, Ref); 507 RefPtr(const RefPtr&); 508 RefPtr& operator=(const RefPtr&); 509 RefPtr(RefPtr&&); 510 RefPtr& operator=(RefPtr&&); 511 ~RefPtr(); 512 513 template <typename U> 514 RefPtr(const RefPtr<U>&); 515 template <typename U> 516 RefPtr& operator=(const RefPtr<U>&); 517 template <typename U> 518 RefPtr(RefPtr&&); 519 template <typename U> 520 RefPtr& operator=(RefPtr&&); 521 522 template <typename U> 523 RefPtr<U> As(); 524 525 bool empty() const; 526 void reset(); 527 528 T* get() const; 529 T* operator->() const; 530 T& operator*() const; 531 explicit operator bool() const; 532 533 Ref ref() const; 534 Store* store() const; 535 536 template <typename U, typename V> 537 friend bool operator==(const RefPtr<U>& lhs, const RefPtr<V>& rhs); 538 template <typename U, typename V> 539 friend bool operator!=(const RefPtr<U>& lhs, const RefPtr<V>& rhs); 540 541 private: 542 template <typename U> 543 friend class RefPtr; 544 545 T* obj_; 546 Store* store_; 547 Store::RootList::Index root_index_; 548 }; 549 550 struct Value { 551 static Value WABT_VECTORCALL Make(s32); 552 static Value WABT_VECTORCALL Make(u32); 553 static Value WABT_VECTORCALL Make(s64); 554 static Value WABT_VECTORCALL Make(u64); 555 static Value WABT_VECTORCALL Make(f32); 556 static Value WABT_VECTORCALL Make(f64); 557 static Value WABT_VECTORCALL Make(v128); 558 static Value WABT_VECTORCALL Make(Ref); 559 template <typename T, u8 L> 560 static Value WABT_VECTORCALL Make(Simd<T, L>); 561 562 template <typename T> 563 T WABT_VECTORCALL Get() const; 564 template <typename T> 565 void WABT_VECTORCALL Set(T); 566 567 private: 568 union { 569 u32 i32_; 570 u64 i64_; 571 f32 f32_; 572 f64 f64_; 573 v128 v128_; 574 Ref ref_; 575 }; 576 577 public: 578 #ifdef WABT_DEBUG 579 Value() : v128_(0, 0, 0, 0), type(ValueType::Any) {} 580 void SetType(ValueType t) { type = t; } 581 void CheckType(ValueType t) const { 582 // Sadly we must allow Any here, since locals may be uninitialized. 583 // Alternatively we could modify InterpAlloca to set the type. 584 assert(t == type || type == ValueType::Any); 585 } 586 ValueType type; 587 #else 588 Value() : v128_(0, 0, 0, 0) {} 589 void SetType(ValueType) {} 590 void CheckType(ValueType) const {} 591 #endif 592 }; 593 using Values = std::vector<Value>; 594 595 struct TypedValue { 596 ValueType type; 597 Value value; 598 }; 599 using TypedValues = std::vector<TypedValue>; 600 601 using Finalizer = std::function<void(Object*)>; 602 603 class Object { 604 public: 605 static bool classof(const Object* obj); 606 static const char* GetTypeName() { return "Object"; } 607 using Ptr = RefPtr<Object>; 608 609 Object(const Object&) = delete; 610 Object& operator=(const Object&) = delete; 611 612 virtual ~Object(); 613 614 ObjectKind kind() const; 615 Ref self() const; 616 617 void* host_info() const; 618 void set_host_info(void*); 619 620 Finalizer get_finalizer() const; 621 void set_finalizer(Finalizer); 622 623 protected: 624 friend Store; 625 explicit Object(ObjectKind); 626 virtual void Mark(Store&) {} 627 628 ObjectKind kind_; 629 Finalizer finalizer_ = nullptr; 630 void* host_info_ = nullptr; 631 Ref self_ = Ref::Null; 632 }; 633 634 class Foreign : public Object { 635 public: 636 static const ObjectKind skind = ObjectKind::Foreign; 637 static bool classof(const Object* obj); 638 static const char* GetTypeName() { return "Foreign"; } 639 using Ptr = RefPtr<Foreign>; 640 641 static Foreign::Ptr New(Store&, void*); 642 643 void* ptr(); 644 645 private: 646 friend Store; 647 explicit Foreign(Store&, void*); 648 void Mark(Store&) override; 649 650 void* ptr_; 651 }; 652 653 class Trap : public Object { 654 public: 655 static const ObjectKind skind = ObjectKind::Trap; 656 static bool classof(const Object* obj); 657 using Ptr = RefPtr<Trap>; 658 659 static Trap::Ptr New(Store&, 660 const std::string& msg, 661 const std::vector<Frame>& trace = std::vector<Frame>()); 662 663 std::string message() const; 664 665 private: 666 friend Store; 667 explicit Trap(Store&, 668 const std::string& msg, 669 const std::vector<Frame>& trace = std::vector<Frame>()); 670 void Mark(Store&) override; 671 672 std::string message_; 673 std::vector<Frame> trace_; 674 }; 675 676 class Exception : public Object { 677 public: 678 static bool classof(const Object* obj); 679 static const ObjectKind skind = ObjectKind::Exception; 680 static const char* GetTypeName() { return "Exception"; } 681 using Ptr = RefPtr<Exception>; 682 683 static Exception::Ptr New(Store&, Ref tag, Values& args); 684 685 Ref tag() const; 686 Values& args(); 687 688 private: 689 friend Store; 690 explicit Exception(Store&, Ref, Values&); 691 void Mark(Store&) override; 692 693 Ref tag_; 694 Values args_; 695 }; 696 697 class Extern : public Object { 698 public: 699 static bool classof(const Object* obj); 700 static const char* GetTypeName() { return "Foreign"; } 701 using Ptr = RefPtr<Extern>; 702 703 virtual Result Match(Store&, const ImportType&, Trap::Ptr* out_trap) = 0; 704 virtual const ExternType& extern_type() = 0; 705 706 protected: 707 friend Store; 708 explicit Extern(ObjectKind); 709 710 template <typename T> 711 Result MatchImpl(Store&, 712 const ImportType&, 713 const T& actual, 714 Trap::Ptr* out_trap); 715 }; 716 717 class Func : public Extern { 718 public: 719 static bool classof(const Object* obj); 720 using Ptr = RefPtr<Func>; 721 722 Result Call(Thread& thread, 723 const Values& params, 724 Values& results, 725 Trap::Ptr* out_trap); 726 727 // Convenience function that creates new Thread. 728 Result Call(Store&, 729 const Values& params, 730 Values& results, 731 Trap::Ptr* out_trap, 732 Stream* = nullptr); 733 734 const ExternType& extern_type() override; 735 const FuncType& type() const; 736 737 protected: 738 explicit Func(ObjectKind, FuncType); 739 virtual Result DoCall(Thread& thread, 740 const Values& params, 741 Values& results, 742 Trap::Ptr* out_trap) = 0; 743 744 FuncType type_; 745 }; 746 747 class DefinedFunc : public Func { 748 public: 749 static bool classof(const Object* obj); 750 static const ObjectKind skind = ObjectKind::DefinedFunc; 751 static const char* GetTypeName() { return "DefinedFunc"; } 752 using Ptr = RefPtr<DefinedFunc>; 753 754 static DefinedFunc::Ptr New(Store&, Ref instance, FuncDesc); 755 756 Result Match(Store&, const ImportType&, Trap::Ptr* out_trap) override; 757 758 Ref instance() const; 759 const FuncDesc& desc() const; 760 761 protected: 762 Result DoCall(Thread& thread, 763 const Values& params, 764 Values& results, 765 Trap::Ptr* out_trap) override; 766 767 private: 768 friend Store; 769 explicit DefinedFunc(Store&, Ref instance, FuncDesc); 770 void Mark(Store&) override; 771 772 Ref instance_; 773 FuncDesc desc_; 774 }; 775 776 class HostFunc : public Func { 777 public: 778 static bool classof(const Object* obj); 779 static const ObjectKind skind = ObjectKind::HostFunc; 780 static const char* GetTypeName() { return "HostFunc"; } 781 using Ptr = RefPtr<HostFunc>; 782 783 using Callback = std::function<Result(Thread& thread, 784 const Values& params, 785 Values& results, 786 Trap::Ptr* out_trap)>; 787 788 static HostFunc::Ptr New(Store&, FuncType, Callback); 789 790 Result Match(Store&, const ImportType&, Trap::Ptr* out_trap) override; 791 792 protected: 793 Result DoCall(Thread& thread, 794 const Values& params, 795 Values& results, 796 Trap::Ptr* out_trap) override; 797 798 private: 799 friend Store; 800 friend Thread; 801 explicit HostFunc(Store&, FuncType, Callback); 802 void Mark(Store&) override; 803 804 Callback callback_; 805 }; 806 807 class Table : public Extern { 808 public: 809 static bool classof(const Object* obj); 810 static const ObjectKind skind = ObjectKind::Table; 811 static const char* GetTypeName() { return "Table"; } 812 using Ptr = RefPtr<Table>; 813 814 static Table::Ptr New(Store&, TableType); 815 816 Result Match(Store&, const ImportType&, Trap::Ptr* out_trap) override; 817 818 bool IsValidRange(u32 offset, u32 size) const; 819 820 Result Get(u32 offset, Ref* out) const; 821 Result Set(Store&, u32 offset, Ref); 822 Result Grow(Store&, u32 count, Ref); 823 Result Fill(Store&, u32 offset, Ref, u32 size); 824 Result Init(Store&, 825 u32 dst_offset, 826 const ElemSegment&, 827 u32 src_offset, 828 u32 size); 829 static Result Copy(Store&, 830 Table& dst, 831 u32 dst_offset, 832 const Table& src, 833 u32 src_offset, 834 u32 size); 835 836 // Unsafe API. 837 Ref UnsafeGet(u32 offset) const; 838 839 const ExternType& extern_type() override; 840 const TableType& type() const; 841 const RefVec& elements() const; 842 u32 size() const; 843 844 private: 845 friend Store; 846 explicit Table(Store&, TableType); 847 void Mark(Store&) override; 848 849 TableType type_; 850 RefVec elements_; 851 }; 852 853 class Memory : public Extern { 854 public: 855 static bool classof(const Object* obj); 856 static const ObjectKind skind = ObjectKind::Memory; 857 static const char* GetTypeName() { return "Memory"; } 858 using Ptr = RefPtr<Memory>; 859 860 static Memory::Ptr New(Store&, MemoryType); 861 862 Result Match(Store&, const ImportType&, Trap::Ptr* out_trap) override; 863 864 bool IsValidAccess(u64 offset, u64 addend, u64 size) const; 865 bool IsValidAtomicAccess(u64 offset, u64 addend, u64 size) const; 866 867 template <typename T> 868 Result Load(u64 offset, u64 addend, T* out) const; 869 template <typename T> 870 Result WABT_VECTORCALL Store(u64 offset, u64 addend, T); 871 Result Grow(u64 pages); 872 Result Fill(u64 offset, u8 value, u64 size); 873 Result Init(u64 dst_offset, const DataSegment&, u64 src_offset, u64 size); 874 static Result Copy(Memory& dst, 875 u64 dst_offset, 876 const Memory& src, 877 u64 src_offset, 878 u64 size); 879 880 // Fake atomics; just checks alignment. 881 template <typename T> 882 Result AtomicLoad(u64 offset, u64 addend, T* out) const; 883 template <typename T> 884 Result AtomicStore(u64 offset, u64 addend, T); 885 template <typename T, typename F> 886 Result AtomicRmw(u64 offset, u64 addend, T, F&& func, T* out); 887 template <typename T> 888 Result AtomicRmwCmpxchg(u64 offset, u64 addend, T expect, T replace, T* out); 889 890 u64 ByteSize() const; 891 u64 PageSize() const; 892 893 // Unsafe API. 894 template <typename T> 895 T WABT_VECTORCALL UnsafeLoad(u64 offset, u64 addend) const; 896 u8* UnsafeData(); 897 898 const ExternType& extern_type() override; 899 const MemoryType& type() const; 900 901 private: 902 friend class Store; 903 explicit Memory(class Store&, MemoryType); 904 void Mark(class Store&) override; 905 906 MemoryType type_; 907 Buffer data_; 908 u64 pages_; 909 }; 910 911 class Global : public Extern { 912 public: 913 static bool classof(const Object* obj); 914 static const ObjectKind skind = ObjectKind::Global; 915 static const char* GetTypeName() { return "Global"; } 916 using Ptr = RefPtr<Global>; 917 918 static Global::Ptr New(Store&, GlobalType, Value); 919 920 Result Match(Store&, const ImportType&, Trap::Ptr* out_trap) override; 921 922 Value Get() const; 923 template <typename T> 924 Result Get(T* out) const; 925 template <typename T> 926 Result WABT_VECTORCALL Set(T); 927 void Set(Store&, Ref); 928 929 template <typename T> 930 T WABT_VECTORCALL UnsafeGet() const; 931 void UnsafeSet(Value); 932 933 const ExternType& extern_type() override; 934 const GlobalType& type() const; 935 936 private: 937 friend Store; 938 explicit Global(Store&, GlobalType, Value); 939 void Mark(Store&) override; 940 941 GlobalType type_; 942 Value value_; 943 }; 944 945 class Tag : public Extern { 946 public: 947 static bool classof(const Object* obj); 948 static const ObjectKind skind = ObjectKind::Tag; 949 static const char* GetTypeName() { return "Tag"; } 950 using Ptr = RefPtr<Tag>; 951 952 static Tag::Ptr New(Store&, TagType); 953 954 Result Match(Store&, const ImportType&, Trap::Ptr* out_trap) override; 955 956 const ExternType& extern_type() override; 957 const TagType& type() const; 958 959 private: 960 friend Store; 961 explicit Tag(Store&, TagType); 962 void Mark(Store&) override; 963 964 TagType type_; 965 }; 966 967 class ElemSegment { 968 public: 969 explicit ElemSegment(Store& store, const ElemDesc*, RefPtr<Instance>&); 970 971 bool IsValidRange(u32 offset, u32 size) const; 972 void Drop(); 973 974 const ElemDesc& desc() const; 975 const RefVec& elements() const; 976 u32 size() const; 977 978 private: 979 friend Instance; 980 void Mark(Store&); 981 982 const ElemDesc* desc_; // Borrowed from the Module. 983 RefVec elements_; 984 }; 985 986 class DataSegment { 987 public: 988 explicit DataSegment(const DataDesc*); 989 990 bool IsValidRange(u64 offset, u64 size) const; 991 void Drop(); 992 993 const DataDesc& desc() const; 994 u64 size() const; 995 996 private: 997 const DataDesc* desc_; // Borrowed from the Module. 998 u64 size_; 999 }; 1000 1001 class Module : public Object { 1002 public: 1003 static bool classof(const Object* obj); 1004 static const ObjectKind skind = ObjectKind::Module; 1005 static const char* GetTypeName() { return "Module"; } 1006 using Ptr = RefPtr<Module>; 1007 1008 static Module::Ptr New(Store&, ModuleDesc); 1009 1010 const ModuleDesc& desc() const; 1011 const std::vector<ImportType>& import_types() const; 1012 const std::vector<ExportType>& export_types() const; 1013 1014 private: 1015 friend Store; 1016 friend Instance; 1017 explicit Module(Store&, ModuleDesc); 1018 void Mark(Store&) override; 1019 1020 ModuleDesc desc_; 1021 std::vector<ImportType> import_types_; 1022 std::vector<ExportType> export_types_; 1023 }; 1024 1025 class Instance : public Object { 1026 public: 1027 static bool classof(const Object* obj); 1028 static const ObjectKind skind = ObjectKind::Instance; 1029 static const char* GetTypeName() { return "Instance"; } 1030 using Ptr = RefPtr<Instance>; 1031 1032 static Instance::Ptr Instantiate(Store&, 1033 Ref module, 1034 const RefVec& imports, 1035 Trap::Ptr* out_trap); 1036 1037 Ref module() const; 1038 const RefVec& imports() const; 1039 const RefVec& funcs() const; 1040 const RefVec& tables() const; 1041 const RefVec& memories() const; 1042 const RefVec& globals() const; 1043 const RefVec& tags() const; 1044 const RefVec& exports() const; 1045 const std::vector<ElemSegment>& elems() const; 1046 std::vector<ElemSegment>& elems(); 1047 const std::vector<DataSegment>& datas() const; 1048 std::vector<DataSegment>& datas(); 1049 1050 private: 1051 friend Store; 1052 friend ElemSegment; 1053 friend DataSegment; 1054 explicit Instance(Store&, Ref module); 1055 void Mark(Store&) override; 1056 1057 Result CallInitFunc(Store&, 1058 const Ref func_ref, 1059 Value* result, 1060 Trap::Ptr* out_trap); 1061 1062 Ref module_; 1063 RefVec imports_; 1064 RefVec funcs_; 1065 RefVec tables_; 1066 RefVec memories_; 1067 RefVec globals_; 1068 RefVec tags_; 1069 RefVec exports_; 1070 std::vector<ElemSegment> elems_; 1071 std::vector<DataSegment> datas_; 1072 }; 1073 1074 enum class RunResult { 1075 Ok, 1076 Return, 1077 Trap, 1078 Exception, 1079 }; 1080 1081 class Thread { 1082 public: 1083 struct Options { 1084 static constexpr u32 kDefaultValueStackSize = 64 * 1024 / sizeof(Value); 1085 static constexpr u32 kDefaultCallStackSize = 64 * 1024 / sizeof(Frame); 1086 1087 u32 value_stack_size = kDefaultValueStackSize; 1088 u32 call_stack_size = kDefaultCallStackSize; 1089 Stream* trace_stream = nullptr; 1090 }; 1091 1092 Thread(Store& store, Stream* trace_stream = nullptr); 1093 ~Thread(); 1094 1095 RunResult Run(Trap::Ptr* out_trap); 1096 RunResult Run(int num_instructions, Trap::Ptr* out_trap); 1097 RunResult Step(Trap::Ptr* out_trap); 1098 1099 Store& store(); 1100 void Mark(); 1101 1102 Instance* GetCallerInstance(); 1103 1104 private: 1105 friend Store; 1106 friend DefinedFunc; 1107 1108 struct TraceSource; 1109 1110 RunResult PushCall(Ref func, u32 offset, Trap::Ptr* out_trap); 1111 RunResult PushCall(const DefinedFunc&, Trap::Ptr* out_trap); 1112 RunResult PushCall(const HostFunc&, Trap::Ptr* out_trap); 1113 RunResult PopCall(); 1114 RunResult DoCall(const Func::Ptr&, Trap::Ptr* out_trap); 1115 RunResult DoReturnCall(const Func::Ptr&, Trap::Ptr* out_trap); 1116 1117 void PushValues(const ValueTypes&, const Values&); 1118 void PopValues(const ValueTypes&, Values*); 1119 1120 Value& Pick(Index); 1121 1122 template <typename T> 1123 T WABT_VECTORCALL Pop(); 1124 Value Pop(); 1125 u64 PopPtr(const Memory::Ptr& memory); 1126 u64 PopPtr(const Table::Ptr& table); 1127 void PushPtr(const Memory::Ptr& memory, u64 value); 1128 void PushPtr(const Table::Ptr& table, u64 value); 1129 1130 template <typename T> 1131 void WABT_VECTORCALL Push(T); 1132 void Push(Value); 1133 void Push(Ref); 1134 1135 template <typename R, typename T> 1136 using UnopFunc = R WABT_VECTORCALL(T); 1137 template <typename R, typename T> 1138 using UnopTrapFunc = RunResult WABT_VECTORCALL(T, R*, std::string*); 1139 template <typename R, typename T> 1140 using BinopFunc = R WABT_VECTORCALL(T, T); 1141 template <typename R, typename T> 1142 using BinopTrapFunc = RunResult WABT_VECTORCALL(T, T, R*, std::string*); 1143 1144 template <typename R, typename T> 1145 RunResult DoUnop(UnopFunc<R, T>); 1146 template <typename R, typename T> 1147 RunResult DoUnop(UnopTrapFunc<R, T>, Trap::Ptr* out_trap); 1148 template <typename R, typename T> 1149 RunResult DoBinop(BinopFunc<R, T>); 1150 template <typename R, typename T> 1151 RunResult DoBinop(BinopTrapFunc<R, T>, Trap::Ptr* out_trap); 1152 1153 template <typename R, typename T> 1154 RunResult DoConvert(Trap::Ptr* out_trap); 1155 template <typename R, typename T> 1156 RunResult DoReinterpret(); 1157 1158 template <typename T> 1159 RunResult Load(Instr, T* out, Trap::Ptr* out_trap); 1160 template <typename T, typename V = T> 1161 RunResult DoLoad(Instr, Trap::Ptr* out_trap); 1162 template <typename T, typename V = T> 1163 RunResult DoStore(Instr, Trap::Ptr* out_trap); 1164 1165 RunResult DoMemoryInit(Instr, Trap::Ptr* out_trap); 1166 RunResult DoDataDrop(Instr); 1167 RunResult DoMemoryCopy(Instr, Trap::Ptr* out_trap); 1168 RunResult DoMemoryFill(Instr, Trap::Ptr* out_trap); 1169 1170 RunResult DoTableInit(Instr, Trap::Ptr* out_trap); 1171 RunResult DoElemDrop(Instr); 1172 RunResult DoTableCopy(Instr, Trap::Ptr* out_trap); 1173 RunResult DoTableGet(Instr, Trap::Ptr* out_trap); 1174 RunResult DoTableSet(Instr, Trap::Ptr* out_trap); 1175 RunResult DoTableGrow(Instr, Trap::Ptr* out_trap); 1176 RunResult DoTableSize(Instr); 1177 RunResult DoTableFill(Instr, Trap::Ptr* out_trap); 1178 1179 template <typename R, typename T> 1180 RunResult DoSimdSplat(); 1181 template <typename R, typename T> 1182 RunResult DoSimdExtract(Instr); 1183 template <typename R, typename T> 1184 RunResult DoSimdReplace(Instr); 1185 1186 template <typename R, typename T> 1187 RunResult DoSimdUnop(UnopFunc<R, T>); 1188 // Like DoSimdUnop but zeroes top half. 1189 template <typename R, typename T> 1190 RunResult DoSimdUnopZero(UnopFunc<R, T>); 1191 template <typename R, typename T> 1192 RunResult DoSimdBinop(BinopFunc<R, T>); 1193 RunResult DoSimdBitSelect(); 1194 template <typename S, u8 count> 1195 RunResult DoSimdIsTrue(); 1196 template <typename S> 1197 RunResult DoSimdBitmask(); 1198 template <typename R, typename T> 1199 RunResult DoSimdShift(BinopFunc<R, T>); 1200 template <typename S> 1201 RunResult DoSimdLoadSplat(Instr, Trap::Ptr* out_trap); 1202 template <typename S> 1203 RunResult DoSimdLoadLane(Instr, Trap::Ptr* out_trap); 1204 template <typename S> 1205 RunResult DoSimdStoreLane(Instr, Trap::Ptr* out_trap); 1206 template <typename S, typename T> 1207 RunResult DoSimdLoadZero(Instr, Trap::Ptr* out_trap); 1208 RunResult DoSimdSwizzle(); 1209 RunResult DoSimdShuffle(Instr); 1210 template <typename S, typename T> 1211 RunResult DoSimdNarrow(); 1212 template <typename S, typename T, bool low> 1213 RunResult DoSimdConvert(); 1214 template <typename S, typename T> 1215 RunResult DoSimdDot(); 1216 template <typename S, typename T> 1217 RunResult DoSimdDotAdd(); 1218 template <typename S> 1219 RunResult DoSimdRelaxedMadd(); 1220 template <typename S> 1221 RunResult DoSimdRelaxedNmadd(); 1222 template <typename S, typename T> 1223 RunResult DoSimdLoadExtend(Instr, Trap::Ptr* out_trap); 1224 template <typename S, typename T> 1225 RunResult DoSimdExtaddPairwise(); 1226 template <typename S, typename T, bool low> 1227 RunResult DoSimdExtmul(); 1228 1229 template <typename T, typename V = T> 1230 RunResult DoAtomicLoad(Instr, Trap::Ptr* out_trap); 1231 template <typename T, typename V = T> 1232 RunResult DoAtomicStore(Instr, Trap::Ptr* out_trap); 1233 template <typename R, typename T> 1234 RunResult DoAtomicRmw(BinopFunc<T, T>, Instr, Trap::Ptr* out_trap); 1235 template <typename T, typename V = T> 1236 RunResult DoAtomicRmwCmpxchg(Instr, Trap::Ptr* out_trap); 1237 1238 RunResult DoThrow(Exception::Ptr exn_ref); 1239 1240 RunResult StepInternal(Trap::Ptr* out_trap); 1241 1242 std::vector<Frame> frames_; 1243 std::vector<Value> values_; 1244 std::vector<u32> refs_; // Index into values_. 1245 1246 // Exception handling requires tracking a separate stack of caught 1247 // exceptions for catch blocks. 1248 RefVec exceptions_; 1249 1250 // Cached for convenience. 1251 Store& store_; 1252 Instance* inst_ = nullptr; 1253 Module* mod_ = nullptr; 1254 1255 // Tracing. 1256 Stream* trace_stream_; 1257 std::unique_ptr<TraceSource> trace_source_; 1258 }; 1259 1260 struct Thread::TraceSource : Istream::TraceSource { 1261 public: 1262 explicit TraceSource(Thread*); 1263 std::string Header(Istream::Offset) override; 1264 std::string Pick(Index, Instr) override; 1265 1266 private: 1267 ValueType GetLocalType(Index); 1268 ValueType GetGlobalType(Index); 1269 ValueType GetTableElementType(Index); 1270 1271 Thread* thread_; 1272 }; 1273 1274 } // namespace interp 1275 } // namespace wabt 1276 1277 #include "wabt/interp/interp-inl.h" 1278 1279 #endif // WABT_INTERP_H_