| /* |
| * Copyright 2020 WebAssembly Community Group participants |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include <cassert> |
| #include <limits> |
| #include <string> |
| |
| namespace wabt { |
| namespace interp { |
| |
| //// Ref //// |
| inline Ref::Ref(size_t index) : index(index) {} |
| |
| inline bool operator==(Ref lhs, Ref rhs) { |
| return lhs.index == rhs.index; |
| } |
| |
| inline bool operator!=(Ref lhs, Ref rhs) { |
| return lhs.index != rhs.index; |
| } |
| |
| //// ExternType //// |
| inline ExternType::ExternType(ExternKind kind) : kind(kind) {} |
| |
| //// FuncType //// |
| // static |
| inline bool FuncType::classof(const ExternType* type) { |
| return type->kind == skind; |
| } |
| |
| inline FuncType::FuncType(ValueTypes params, ValueTypes results) |
| : ExternType(ExternKind::Func), params(params), results(results) {} |
| |
| //// TableType //// |
| // static |
| inline bool TableType::classof(const ExternType* type) { |
| return type->kind == skind; |
| } |
| |
| inline TableType::TableType(ValueType element, Limits limits) |
| : ExternType(ExternKind::Table), element(element), limits(limits) { |
| // Always set max. |
| if (!limits.has_max) { |
| this->limits.max = std::numeric_limits<u32>::max(); |
| } |
| } |
| |
| //// MemoryType //// |
| // static |
| inline bool MemoryType::classof(const ExternType* type) { |
| return type->kind == skind; |
| } |
| |
| inline MemoryType::MemoryType(Limits limits) |
| : ExternType(ExternKind::Memory), limits(limits) { |
| // Always set max. |
| if (!limits.has_max) { |
| this->limits.max = limits.is_64 ? WABT_MAX_PAGES64 : WABT_MAX_PAGES32; |
| } |
| } |
| |
| //// GlobalType //// |
| // static |
| inline bool GlobalType::classof(const ExternType* type) { |
| return type->kind == skind; |
| } |
| |
| inline GlobalType::GlobalType(ValueType type, Mutability mut) |
| : ExternType(ExternKind::Global), type(type), mut(mut) {} |
| |
| //// TagType //// |
| // static |
| inline bool TagType::classof(const ExternType* type) { |
| return type->kind == skind; |
| } |
| |
| inline TagType::TagType(TagAttr attr, const ValueTypes& signature) |
| : ExternType(ExternKind::Tag), attr(attr), signature(signature) {} |
| |
| //// ImportType //// |
| inline ImportType::ImportType(std::string module, |
| std::string name, |
| std::unique_ptr<ExternType> type) |
| : module(module), name(name), type(std::move(type)) {} |
| |
| inline ImportType::ImportType(const ImportType& other) |
| : module(other.module), name(other.name), type(other.type->Clone()) {} |
| |
| inline ImportType& ImportType::operator=(const ImportType& other) { |
| if (this != &other) { |
| module = other.module; |
| name = other.name; |
| type = other.type->Clone(); |
| } |
| return *this; |
| } |
| |
| //// ExportType //// |
| inline ExportType::ExportType(std::string name, |
| std::unique_ptr<ExternType> type) |
| : name(name), type(std::move(type)) {} |
| |
| inline ExportType::ExportType(const ExportType& other) |
| : name(other.name), type(other.type->Clone()) {} |
| |
| inline ExportType& ExportType::operator=(const ExportType& other) { |
| if (this != &other) { |
| name = other.name; |
| type = other.type->Clone(); |
| } |
| return *this; |
| } |
| |
| //// Frame //// |
| inline Frame::Frame(Ref func, |
| u32 values, |
| u32 exceptions, |
| u32 offset, |
| Instance* inst, |
| Module* mod) |
| : func(func), |
| values(values), |
| exceptions(exceptions), |
| offset(offset), |
| inst(inst), |
| mod(mod) {} |
| |
| //// FreeList //// |
| template <typename T> |
| bool FreeList<T>::IsUsed(Index index) const { |
| return index < list_.size() && !is_free_[index]; |
| } |
| |
| template <typename T> |
| template <typename... Args> |
| auto FreeList<T>::New(Args&&... args) -> Index { |
| if (!free_.empty()) { |
| Index index = free_.back(); |
| assert(is_free_[index]); |
| free_.pop_back(); |
| is_free_[index] = false; |
| list_[index] = T(std::forward<Args>(args)...); |
| return index; |
| } |
| assert(list_.size() == is_free_.size()); |
| is_free_.push_back(false); |
| list_.emplace_back(std::forward<Args>(args)...); |
| return list_.size() - 1; |
| } |
| |
| template <typename T> |
| void FreeList<T>::Delete(Index index) { |
| list_[index] = T(); |
| is_free_[index] = true; |
| free_.push_back(index); |
| } |
| |
| template <typename T> |
| const T& FreeList<T>::Get(Index index) const { |
| assert(IsUsed(index)); |
| return list_[index]; |
| } |
| |
| template <typename T> |
| T& FreeList<T>::Get(Index index) { |
| assert(IsUsed(index)); |
| return list_[index]; |
| } |
| |
| template <typename T> |
| auto FreeList<T>::size() const -> Index { |
| return list_.size(); |
| } |
| |
| template <typename T> |
| auto FreeList<T>::count() const -> Index { |
| return list_.size() - free_.size(); |
| } |
| |
| //// RefPtr //// |
| template <typename T> |
| RefPtr<T>::RefPtr() : obj_(nullptr), store_(nullptr), root_index_(0) {} |
| |
| template <typename T> |
| RefPtr<T>::RefPtr(Store& store, Ref ref) { |
| #ifndef NDEBUG |
| if (!store.Is<T>(ref)) { |
| ObjectKind ref_kind; |
| if (ref == Ref::Null) { |
| ref_kind = ObjectKind::Null; |
| } else { |
| ref_kind = store.objects_.Get(ref.index)->kind(); |
| } |
| fprintf(stderr, "Invalid conversion from Ref (%s) to RefPtr<%s>!\n", |
| GetName(ref_kind), T::GetTypeName()); |
| abort(); |
| } |
| #endif |
| root_index_ = store.NewRoot(ref); |
| obj_ = static_cast<T*>(store.objects_.Get(ref.index).get()); |
| store_ = &store; |
| } |
| |
| template <typename T> |
| RefPtr<T>::RefPtr(const RefPtr& other) |
| : obj_(other.obj_), store_(other.store_) { |
| root_index_ = store_ ? store_->CopyRoot(other.root_index_) : 0; |
| } |
| |
| template <typename T> |
| RefPtr<T>& RefPtr<T>::operator=(const RefPtr& other) { |
| obj_ = other.obj_; |
| store_ = other.store_; |
| root_index_ = store_ ? store_->CopyRoot(other.root_index_) : 0; |
| return *this; |
| } |
| |
| template <typename T> |
| RefPtr<T>::RefPtr(RefPtr&& other) |
| : obj_(other.obj_), store_(other.store_), root_index_(other.root_index_) { |
| other.obj_ = nullptr; |
| other.store_ = nullptr; |
| other.root_index_ = 0; |
| } |
| |
| template <typename T> |
| RefPtr<T>& RefPtr<T>::operator=(RefPtr&& other) { |
| obj_ = other.obj_; |
| store_ = other.store_; |
| root_index_ = other.root_index_; |
| other.obj_ = nullptr; |
| other.store_ = nullptr; |
| other.root_index_ = 0; |
| return *this; |
| } |
| |
| template <typename T> |
| RefPtr<T>::~RefPtr() { |
| reset(); |
| } |
| |
| template <typename T> |
| template <typename U> |
| RefPtr<T>::RefPtr(const RefPtr<U>& other) |
| : obj_(other.obj_), store_(other.store_) { |
| root_index_ = store_ ? store_->CopyRoot(other.root_index_) : 0; |
| } |
| |
| template <typename T> |
| template <typename U> |
| RefPtr<T>& RefPtr<T>::operator=(const RefPtr<U>& other){ |
| obj_ = other.obj_; |
| store_ = other.store_; |
| root_index_ = store_ ? store_->CopyRoot(other.root_index_) : 0; |
| return *this; |
| } |
| |
| template <typename T> |
| template <typename U> |
| RefPtr<T>::RefPtr(RefPtr&& other) |
| : obj_(other.obj_), store_(other.store_), root_index_(other.root_index_) { |
| other.obj_ = nullptr; |
| other.store_ = nullptr; |
| other.root_index_ = 0; |
| } |
| |
| template <typename T> |
| template <typename U> |
| RefPtr<T>& RefPtr<T>::operator=(RefPtr&& other) { |
| obj_ = other.obj_; |
| store_ = other.store_; |
| root_index_ = other.root_index_; |
| other.obj_ = nullptr; |
| other.store_ = nullptr; |
| other.root_index_ = 0; |
| return *this; |
| } |
| |
| template <typename T> |
| template <typename U> |
| RefPtr<U> RefPtr<T>::As() { |
| static_assert(std::is_base_of<T, U>::value, "T must be base class of U"); |
| assert(store_->Is<U>(obj_->self())); |
| RefPtr<U> result; |
| result.obj_ = static_cast<U*>(obj_); |
| result.store_ = store_; |
| result.root_index_ = store_->CopyRoot(root_index_); |
| return result; |
| } |
| |
| template <typename T> |
| bool RefPtr<T>::empty() const { |
| return obj_ == nullptr; |
| } |
| |
| template <typename T> |
| void RefPtr<T>::reset() { |
| if (obj_) { |
| store_->DeleteRoot(root_index_); |
| obj_ = nullptr; |
| root_index_ = 0; |
| store_ = nullptr; |
| } |
| } |
| |
| template <typename T> |
| T* RefPtr<T>::get() const { |
| return obj_; |
| } |
| |
| template <typename T> |
| T* RefPtr<T>::operator->() const { |
| return obj_; |
| } |
| |
| template <typename T> |
| T& RefPtr<T>::operator*() const { |
| return *obj_; |
| } |
| |
| template <typename T> |
| RefPtr<T>::operator bool() const { |
| return obj_ != nullptr; |
| } |
| |
| template <typename T> |
| Ref RefPtr<T>::ref() const { |
| return store_ ? store_->roots_.Get(root_index_) : Ref::Null; |
| } |
| |
| template <typename T> |
| Store* RefPtr<T>::store() const { |
| return store_; |
| } |
| |
| template <typename U, typename V> |
| bool operator==(const RefPtr<U>& lhs, const RefPtr<V>& rhs) { |
| return lhs.obj_->self() == rhs.obj_->self(); |
| } |
| |
| template <typename U, typename V> |
| bool operator!=(const RefPtr<U>& lhs, const RefPtr<V>& rhs) { |
| return lhs.obj_->self() != rhs.obj_->self(); |
| } |
| |
| //// ValueType //// |
| inline bool IsReference(ValueType type) { return type.IsRef(); } |
| template <> inline bool HasType<s32>(ValueType type) { return type == ValueType::I32; } |
| template <> inline bool HasType<u32>(ValueType type) { return type == ValueType::I32; } |
| template <> inline bool HasType<s64>(ValueType type) { return type == ValueType::I64; } |
| template <> inline bool HasType<u64>(ValueType type) { return type == ValueType::I64; } |
| template <> inline bool HasType<f32>(ValueType type) { return type == ValueType::F32; } |
| template <> inline bool HasType<f64>(ValueType type) { return type == ValueType::F64; } |
| template <> inline bool HasType<Ref>(ValueType type) { return IsReference(type); } |
| |
| template <typename T> void RequireType(ValueType type) { |
| assert(HasType<T>(type)); |
| } |
| |
| inline bool TypesMatch(ValueType expected, ValueType actual) { |
| // Currently there is no subtyping, so expected and actual must match |
| // exactly. In the future this may be expanded. |
| return expected == actual; |
| } |
| |
| //// Value //// |
| inline Value WABT_VECTORCALL Value::Make(s32 val) { Value res; res.i32_ = val; res.SetType(ValueType::I32); return res; } |
| inline Value WABT_VECTORCALL Value::Make(u32 val) { Value res; res.i32_ = val; res.SetType(ValueType::I32); return res; } |
| inline Value WABT_VECTORCALL Value::Make(s64 val) { Value res; res.i64_ = val; res.SetType(ValueType::I64); return res; } |
| inline Value WABT_VECTORCALL Value::Make(u64 val) { Value res; res.i64_ = val; res.SetType(ValueType::I64); return res; } |
| inline Value WABT_VECTORCALL Value::Make(f32 val) { Value res; res.f32_ = val; res.SetType(ValueType::F32); return res; } |
| inline Value WABT_VECTORCALL Value::Make(f64 val) { Value res; res.f64_ = val; res.SetType(ValueType::F64); return res; } |
| inline Value WABT_VECTORCALL Value::Make(v128 val) { Value res; res.v128_ = val; res.SetType(ValueType::V128); return res; } |
| inline Value WABT_VECTORCALL Value::Make(Ref val) { Value res; res.ref_ = val; res.SetType(ValueType::ExternRef); return res; } |
| template <typename T, u8 L> |
| Value WABT_VECTORCALL Value::Make(Simd<T, L> val) { |
| Value res; |
| res.v128_ = Bitcast<v128>(val); |
| res.SetType(ValueType::V128); |
| return res; |
| } |
| |
| template <> inline s8 WABT_VECTORCALL Value::Get<s8>() const { CheckType(ValueType::I32); return i32_; } |
| template <> inline u8 WABT_VECTORCALL Value::Get<u8>() const { CheckType(ValueType::I32); return i32_; } |
| template <> inline s16 WABT_VECTORCALL Value::Get<s16>() const { CheckType(ValueType::I32); return i32_; } |
| template <> inline u16 WABT_VECTORCALL Value::Get<u16>() const { CheckType(ValueType::I32); return i32_; } |
| template <> inline s32 WABT_VECTORCALL Value::Get<s32>() const { CheckType(ValueType::I32); return i32_; } |
| template <> inline u32 WABT_VECTORCALL Value::Get<u32>() const { CheckType(ValueType::I32); return i32_; } |
| template <> inline s64 WABT_VECTORCALL Value::Get<s64>() const { CheckType(ValueType::I64); return i64_; } |
| template <> inline u64 WABT_VECTORCALL Value::Get<u64>() const { CheckType(ValueType::I64); return i64_; } |
| template <> inline f32 WABT_VECTORCALL Value::Get<f32>() const { CheckType(ValueType::F32); return f32_; } |
| template <> inline f64 WABT_VECTORCALL Value::Get<f64>() const { CheckType(ValueType::F64); return f64_; } |
| template <> inline v128 WABT_VECTORCALL Value::Get<v128>() const { CheckType(ValueType::V128); return v128_; } |
| template <> inline Ref WABT_VECTORCALL Value::Get<Ref>() const { CheckType(ValueType::ExternRef); return ref_; } |
| |
| template <> inline s8x16 WABT_VECTORCALL Value::Get<s8x16>() const { CheckType(ValueType::V128); return Bitcast<s8x16>(v128_); } |
| template <> inline u8x16 WABT_VECTORCALL Value::Get<u8x16>() const { CheckType(ValueType::V128); return Bitcast<u8x16>(v128_); } |
| template <> inline s16x8 WABT_VECTORCALL Value::Get<s16x8>() const { CheckType(ValueType::V128); return Bitcast<s16x8>(v128_); } |
| template <> inline u16x8 WABT_VECTORCALL Value::Get<u16x8>() const { CheckType(ValueType::V128); return Bitcast<u16x8>(v128_); } |
| template <> inline s32x4 WABT_VECTORCALL Value::Get<s32x4>() const { CheckType(ValueType::V128); return Bitcast<s32x4>(v128_); } |
| template <> inline u32x4 WABT_VECTORCALL Value::Get<u32x4>() const { CheckType(ValueType::V128); return Bitcast<u32x4>(v128_); } |
| template <> inline s64x2 WABT_VECTORCALL Value::Get<s64x2>() const { CheckType(ValueType::V128); return Bitcast<s64x2>(v128_); } |
| template <> inline u64x2 WABT_VECTORCALL Value::Get<u64x2>() const { CheckType(ValueType::V128); return Bitcast<u64x2>(v128_); } |
| template <> inline f32x4 WABT_VECTORCALL Value::Get<f32x4>() const { CheckType(ValueType::V128); return Bitcast<f32x4>(v128_); } |
| template <> inline f64x2 WABT_VECTORCALL Value::Get<f64x2>() const { CheckType(ValueType::V128); return Bitcast<f64x2>(v128_); } |
| |
| template <> inline void WABT_VECTORCALL Value::Set<s32>(s32 val) { i32_ = val; SetType(ValueType::I32); } |
| template <> inline void WABT_VECTORCALL Value::Set<u32>(u32 val) { i32_ = val; SetType(ValueType::I32); } |
| template <> inline void WABT_VECTORCALL Value::Set<s64>(s64 val) { i64_ = val; SetType(ValueType::I64); } |
| template <> inline void WABT_VECTORCALL Value::Set<u64>(u64 val) { i64_ = val; SetType(ValueType::I64); } |
| template <> inline void WABT_VECTORCALL Value::Set<f32>(f32 val) { f32_ = val; SetType(ValueType::F32); } |
| template <> inline void WABT_VECTORCALL Value::Set<f64>(f64 val) { f64_ = val; SetType(ValueType::F64); } |
| template <> inline void WABT_VECTORCALL Value::Set<v128>(v128 val) { v128_ = val; SetType(ValueType::V128); } |
| template <> inline void WABT_VECTORCALL Value::Set<Ref>(Ref val) { ref_ = val; SetType(ValueType::ExternRef); } |
| |
| //// Store //// |
| inline bool Store::IsValid(Ref ref) const { |
| return objects_.IsUsed(ref.index) && objects_.Get(ref.index); |
| } |
| |
| template <typename T> |
| bool Store::Is(Ref ref) const { |
| return objects_.IsUsed(ref.index) && isa<T>(objects_.Get(ref.index).get()); |
| } |
| |
| template <typename T> |
| Result Store::Get(Ref ref, RefPtr<T>* out) { |
| if (Is<T>(ref)) { |
| *out = RefPtr<T>(*this, ref); |
| return Result::Ok; |
| } |
| return Result::Error; |
| } |
| |
| template <typename T> |
| RefPtr<T> Store::UnsafeGet(Ref ref) { |
| return RefPtr<T>(*this, ref); |
| } |
| |
| template <typename T, typename... Args> |
| RefPtr<T> Store::Alloc(Args&&... args) { |
| Ref ref{objects_.New(new T(std::forward<Args>(args)...))}; |
| RefPtr<T> ptr{*this, ref}; |
| ptr->self_ = ref; |
| return ptr; |
| } |
| |
| inline Store::ObjectList::Index Store::object_count() const { |
| return objects_.count(); |
| } |
| |
| inline const Features& Store::features() const { |
| return features_; |
| } |
| |
| //// Object //// |
| // static |
| inline bool Object::classof(const Object* obj) { |
| return true; |
| } |
| |
| inline Object::Object(ObjectKind kind) : kind_(kind) {} |
| |
| inline ObjectKind Object::kind() const { |
| return kind_; |
| } |
| |
| inline Ref Object::self() const { |
| return self_; |
| } |
| |
| inline void* Object::host_info() const { |
| return host_info_; |
| } |
| |
| inline void Object::set_host_info(void* host_info) { |
| host_info_ = host_info; |
| } |
| |
| inline Finalizer Object::get_finalizer() const { |
| return finalizer_; |
| } |
| |
| inline void Object::set_finalizer(Finalizer finalizer) { |
| finalizer_ = finalizer; |
| } |
| |
| //// Foreign //// |
| // static |
| inline bool Foreign::classof(const Object* obj) { |
| return obj->kind() == skind; |
| } |
| |
| // static |
| inline Foreign::Ptr Foreign::New(Store& store, void* ptr) { |
| return store.Alloc<Foreign>(store, ptr); |
| } |
| |
| inline void* Foreign::ptr() { |
| return ptr_; |
| } |
| |
| //// Trap //// |
| // static |
| inline bool Trap::classof(const Object* obj) { |
| return obj->kind() == skind; |
| } |
| |
| // static |
| inline Trap::Ptr Trap::New(Store& store, |
| const std::string& msg, |
| const std::vector<Frame>& trace) { |
| return store.Alloc<Trap>(store, msg, trace); |
| } |
| |
| inline std::string Trap::message() const { |
| return message_; |
| } |
| |
| //// Exception //// |
| // static |
| inline bool Exception::classof(const Object* obj) { |
| return obj->kind() == skind; |
| } |
| |
| // static |
| inline Exception::Ptr Exception::New(Store& store, Ref tag, Values& args) { |
| return store.Alloc<Exception>(store, tag, args); |
| } |
| |
| inline Ref Exception::tag() const { |
| return tag_; |
| } |
| |
| inline Values& Exception::args() { |
| return args_; |
| } |
| |
| //// Extern //// |
| // static |
| inline bool Extern::classof(const Object* obj) { |
| switch (obj->kind()) { |
| case ObjectKind::DefinedFunc: |
| case ObjectKind::HostFunc: |
| case ObjectKind::Table: |
| case ObjectKind::Memory: |
| case ObjectKind::Global: |
| case ObjectKind::Tag: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| inline Extern::Extern(ObjectKind kind) : Object(kind) {} |
| |
| //// Func //// |
| // static |
| inline bool Func::classof(const Object* obj) { |
| switch (obj->kind()) { |
| case ObjectKind::DefinedFunc: |
| case ObjectKind::HostFunc: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| inline const ExternType& Func::extern_type() { |
| return type_; |
| } |
| |
| inline const FuncType& Func::type() const { |
| return type_; |
| } |
| |
| //// DefinedFunc //// |
| // static |
| inline bool DefinedFunc::classof(const Object* obj) { |
| return obj->kind() == skind; |
| } |
| |
| // static |
| inline DefinedFunc::Ptr DefinedFunc::New(Store& store, |
| Ref instance, |
| FuncDesc desc) { |
| return store.Alloc<DefinedFunc>(store, instance, desc); |
| } |
| |
| inline Ref DefinedFunc::instance() const { |
| return instance_; |
| } |
| |
| inline const FuncDesc& DefinedFunc::desc() const { |
| return desc_; |
| } |
| |
| //// HostFunc //// |
| // static |
| inline bool HostFunc::classof(const Object* obj) { |
| return obj->kind() == skind; |
| } |
| |
| // static |
| inline HostFunc::Ptr HostFunc::New(Store& store, FuncType type, Callback cb) { |
| return store.Alloc<HostFunc>(store, type, cb); |
| } |
| |
| //// Table //// |
| // static |
| inline bool Table::classof(const Object* obj) { |
| return obj->kind() == skind; |
| } |
| |
| // static |
| inline Table::Ptr Table::New(Store& store, TableType type) { |
| return store.Alloc<Table>(store, type); |
| } |
| |
| inline const ExternType& Table::extern_type() { |
| return type_; |
| } |
| |
| inline const TableType& Table::type() const { |
| return type_; |
| } |
| |
| inline const RefVec& Table::elements() const { |
| return elements_; |
| } |
| |
| inline u32 Table::size() const { |
| return static_cast<u32>(elements_.size()); |
| } |
| |
| //// Memory //// |
| // static |
| inline bool Memory::classof(const Object* obj) { |
| return obj->kind() == skind; |
| } |
| |
| // static |
| inline Memory::Ptr Memory::New(interp::Store& store, MemoryType type) { |
| return store.Alloc<Memory>(store, type); |
| } |
| |
| inline bool Memory::IsValidAccess(u64 offset, u64 addend, u64 size) const { |
| // FIXME: make this faster. |
| return offset <= data_.size() && |
| addend <= data_.size() && |
| size <= data_.size() && |
| offset + addend + size <= data_.size(); |
| } |
| |
| inline bool Memory::IsValidAtomicAccess(u64 offset, |
| u64 addend, |
| u64 size) const { |
| return IsValidAccess(offset, addend, size) && |
| ((offset + addend) & (size - 1)) == 0; |
| } |
| |
| template <typename T> |
| Result Memory::Load(u64 offset, u64 addend, T* out) const { |
| if (!IsValidAccess(offset, addend, sizeof(T))) { |
| return Result::Error; |
| } |
| wabt::MemcpyEndianAware(out, data_.data(), sizeof(T), data_.size(), 0, offset + addend, sizeof(T)); |
| return Result::Ok; |
| } |
| |
| template <typename T> |
| T WABT_VECTORCALL Memory::UnsafeLoad(u64 offset, u64 addend) const { |
| assert(IsValidAccess(offset, addend, sizeof(T))); |
| T val; |
| wabt::MemcpyEndianAware(&val, data_.data(), sizeof(T), data_.size(), 0, offset + addend, sizeof(T)); |
| return val; |
| } |
| |
| template <typename T> |
| Result WABT_VECTORCALL Memory::Store(u64 offset, u64 addend, T val) { |
| if (!IsValidAccess(offset, addend, sizeof(T))) { |
| return Result::Error; |
| } |
| wabt::MemcpyEndianAware(data_.data(), &val, data_.size(), sizeof(T), offset + addend, 0, sizeof(T)); |
| return Result::Ok; |
| } |
| |
| template <typename T> |
| Result Memory::AtomicLoad(u64 offset, u64 addend, T* out) const { |
| if (!IsValidAtomicAccess(offset, addend, sizeof(T))) { |
| return Result::Error; |
| } |
| wabt::MemcpyEndianAware(out, data_.data(), sizeof(T), data_.size(), 0, offset + addend, sizeof(T)); |
| return Result::Ok; |
| } |
| |
| template <typename T> |
| Result Memory::AtomicStore(u64 offset, u64 addend, T val) { |
| if (!IsValidAtomicAccess(offset, addend, sizeof(T))) { |
| return Result::Error; |
| } |
| wabt::MemcpyEndianAware(data_.data(), &val, data_.size(), sizeof(T), offset + addend, 0, sizeof(T)); |
| return Result::Ok; |
| } |
| |
| template <typename T, typename F> |
| Result Memory::AtomicRmw(u64 offset, u64 addend, T rhs, F&& func, T* out) { |
| T lhs; |
| CHECK_RESULT(AtomicLoad(offset, addend, &lhs)); |
| CHECK_RESULT(AtomicStore(offset, addend, func(lhs, rhs))); |
| *out = lhs; |
| return Result::Ok; |
| } |
| |
| template <typename T> |
| Result Memory::AtomicRmwCmpxchg(u64 offset, |
| u64 addend, |
| T expect, |
| T replace, |
| T* out) { |
| T read; |
| CHECK_RESULT(AtomicLoad(offset, addend, &read)); |
| if (read == expect) { |
| CHECK_RESULT(AtomicStore(offset, addend, replace)); |
| } |
| *out = read; |
| return Result::Ok; |
| } |
| |
| inline u8* Memory::UnsafeData() { |
| return data_.data(); |
| } |
| |
| inline u64 Memory::ByteSize() const { |
| return data_.size(); |
| } |
| |
| inline u64 Memory::PageSize() const { |
| return pages_; |
| } |
| |
| inline const ExternType& Memory::extern_type() { |
| return type_; |
| } |
| |
| inline const MemoryType& Memory::type() const { |
| return type_; |
| } |
| |
| //// Global //// |
| // static |
| inline bool Global::classof(const Object* obj) { |
| return obj->kind() == skind; |
| } |
| |
| // static |
| inline Global::Ptr Global::New(Store& store, GlobalType type, Value value) { |
| return store.Alloc<Global>(store, type, value); |
| } |
| |
| inline Value Global::Get() const { |
| return value_; |
| } |
| |
| template <typename T> |
| Result Global::Get(T* out) const { |
| if (HasType<T>(type_.type)) { |
| *out = value_.Get<T>(); |
| return Result::Ok; |
| } |
| return Result::Error; |
| } |
| |
| template <typename T> |
| T WABT_VECTORCALL Global::UnsafeGet() const { |
| RequireType<T>(type_.type); |
| return value_.Get<T>(); |
| } |
| |
| template <typename T> |
| Result WABT_VECTORCALL Global::Set(T val) { |
| if (type_.mut == Mutability::Var && HasType<T>(type_.type)) { |
| value_.Set(val); |
| return Result::Ok; |
| } |
| return Result::Error; |
| } |
| |
| inline const ExternType& Global::extern_type() { |
| return type_; |
| } |
| |
| inline const GlobalType& Global::type() const { |
| return type_; |
| } |
| |
| //// Tag //// |
| // static |
| inline bool Tag::classof(const Object* obj) { |
| return obj->kind() == skind; |
| } |
| |
| // static |
| inline Tag::Ptr Tag::New(Store& store, TagType type) { |
| return store.Alloc<Tag>(store, type); |
| } |
| |
| inline const ExternType& Tag::extern_type() { |
| return type_; |
| } |
| |
| inline const TagType& Tag::type() const { |
| return type_; |
| } |
| |
| //// ElemSegment //// |
| inline void ElemSegment::Drop() { |
| elements_.clear(); |
| } |
| |
| inline const ElemDesc& ElemSegment::desc() const { |
| return *desc_; |
| } |
| |
| inline const RefVec& ElemSegment::elements() const { |
| return elements_; |
| } |
| |
| inline u32 ElemSegment::size() const { |
| return elements_.size(); |
| } |
| |
| //// DataSegment //// |
| inline void DataSegment::Drop() { |
| size_ = 0; |
| } |
| |
| inline const DataDesc& DataSegment::desc() const { |
| return *desc_; |
| } |
| |
| inline u64 DataSegment::size() const { |
| return size_; |
| } |
| |
| //// Module //// |
| // static |
| inline bool Module::classof(const Object* obj) { |
| return obj->kind() == skind; |
| } |
| |
| // static |
| inline Module::Ptr Module::New(Store& store, ModuleDesc desc) { |
| return store.Alloc<Module>(store, std::move(desc)); |
| } |
| |
| inline const ModuleDesc& Module::desc() const { |
| return desc_; |
| } |
| |
| inline const std::vector<ImportType>& Module::import_types() const { |
| return import_types_; |
| } |
| |
| inline const std::vector<ExportType>& Module::export_types() const { |
| return export_types_; |
| } |
| |
| //// Instance //// |
| // static |
| inline bool Instance::classof(const Object* obj) { |
| return obj->kind() == skind; |
| } |
| |
| inline Ref Instance::module() const { |
| return module_; |
| } |
| |
| inline const RefVec& Instance::imports() const { |
| return imports_; |
| } |
| |
| inline const RefVec& Instance::funcs() const { |
| return funcs_; |
| } |
| |
| inline const RefVec& Instance::tables() const { |
| return tables_; |
| } |
| |
| inline const RefVec& Instance::memories() const { |
| return memories_; |
| } |
| |
| inline const RefVec& Instance::globals() const { |
| return globals_; |
| } |
| |
| inline const RefVec& Instance::tags() const { |
| return tags_; |
| } |
| |
| inline const RefVec& Instance::exports() const { |
| return exports_; |
| } |
| |
| inline const std::vector<ElemSegment>& Instance::elems() const { |
| return elems_; |
| } |
| |
| inline std::vector<ElemSegment>& Instance::elems() { |
| return elems_; |
| } |
| |
| inline const std::vector<DataSegment>& Instance::datas() const { |
| return datas_; |
| } |
| |
| inline std::vector<DataSegment>& Instance::datas() { |
| return datas_; |
| } |
| |
| //// Thread //// |
| // static |
| inline bool Thread::classof(const Object* obj) { |
| return obj->kind() == skind; |
| } |
| |
| // static |
| inline Thread::Ptr Thread::New(Store& store, const Options& options) { |
| return store.Alloc<Thread>(store, options); |
| } |
| |
| inline Store& Thread::store() { |
| return store_; |
| } |
| |
| } // namespace interp |
| } // namespace wabt |