| /* |
| * Copyright 2016 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. |
| */ |
| |
| #ifndef WABT_COMMON_H_ |
| #define WABT_COMMON_H_ |
| |
| #include <algorithm> |
| #include <cassert> |
| #include <cstdarg> |
| #include <cstddef> |
| #include <cstdint> |
| #include <cstdio> |
| #include <cstdlib> |
| #include <cstring> |
| #include <memory> |
| #include <string> |
| #include <string_view> |
| #include <type_traits> |
| #include <vector> |
| |
| #include "wabt/config.h" |
| |
| #include "wabt/base-types.h" |
| #include "wabt/result.h" |
| #include "wabt/string-format.h" |
| #include "wabt/type.h" |
| |
| #define WABT_FATAL(...) fprintf(stderr, __VA_ARGS__), exit(1) |
| #define WABT_ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) |
| |
| #define WABT_USE(x) static_cast<void>(x) |
| |
| // 64k |
| #define WABT_PAGE_SIZE 0x10000 |
| // # of pages that fit in 32-bit address space |
| #define WABT_MAX_PAGES32 0x10000 |
| // # of pages that fit in 64-bit address space |
| #define WABT_MAX_PAGES64 0x1000000000000 |
| #define WABT_BYTES_TO_PAGES(x) ((x) >> 16) |
| #define WABT_ALIGN_UP_TO_PAGE(x) \ |
| (((x) + WABT_PAGE_SIZE - 1) & ~(WABT_PAGE_SIZE - 1)) |
| |
| #define WABT_ENUM_COUNT(name) \ |
| (static_cast<int>(name::Last) - static_cast<int>(name::First) + 1) |
| |
| #define WABT_DISALLOW_COPY_AND_ASSIGN(type) \ |
| type(const type&) = delete; \ |
| type& operator=(const type&) = delete; |
| |
| #if WITH_EXCEPTIONS |
| #define WABT_TRY try { |
| #define WABT_CATCH_BAD_ALLOC \ |
| } \ |
| catch (std::bad_alloc&) { \ |
| } |
| #define WABT_CATCH_BAD_ALLOC_AND_EXIT \ |
| } \ |
| catch (std::bad_alloc&) { \ |
| WABT_FATAL("Memory allocation failure.\n"); \ |
| } |
| #else |
| #define WABT_TRY |
| #define WABT_CATCH_BAD_ALLOC |
| #define WABT_CATCH_BAD_ALLOC_AND_EXIT |
| #endif |
| |
| #define PRIindex "u" |
| #define PRIaddress PRIu64 |
| #define PRIoffset PRIzx |
| |
| namespace wabt { |
| inline void MemcpyEndianAware(void* dst, |
| const void* src, |
| size_t dsize, |
| size_t ssize, |
| size_t doff, |
| size_t soff, |
| size_t len) { |
| #if WABT_BIG_ENDIAN |
| memcpy(static_cast<char*>(dst) + (dsize) - (len) - (doff), |
| static_cast<const char*>(src) + (ssize) - (len) - (soff), (len)); |
| #else |
| memcpy(static_cast<char*>(dst) + (doff), |
| static_cast<const char*>(src) + (soff), (len)); |
| #endif |
| } |
| } |
| |
| struct v128 { |
| v128() = default; |
| v128(uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3) { |
| set_u32(0, x0); |
| set_u32(1, x1); |
| set_u32(2, x2); |
| set_u32(3, x3); |
| } |
| |
| bool operator==(const v128& other) const { |
| return std::equal(std::begin(v), std::end(v), std::begin(other.v)); |
| } |
| bool operator!=(const v128& other) const { return !(*this == other); } |
| |
| uint8_t u8(int lane) const { return To<uint8_t>(lane); } |
| uint16_t u16(int lane) const { return To<uint16_t>(lane); } |
| uint32_t u32(int lane) const { return To<uint32_t>(lane); } |
| uint64_t u64(int lane) const { return To<uint64_t>(lane); } |
| uint32_t f32_bits(int lane) const { return To<uint32_t>(lane); } |
| uint64_t f64_bits(int lane) const { return To<uint64_t>(lane); } |
| |
| void set_u8(int lane, uint8_t x) { return From<uint8_t>(lane, x); } |
| void set_u16(int lane, uint16_t x) { return From<uint16_t>(lane, x); } |
| void set_u32(int lane, uint32_t x) { return From<uint32_t>(lane, x); } |
| void set_u64(int lane, uint64_t x) { return From<uint64_t>(lane, x); } |
| void set_f32_bits(int lane, uint32_t x) { return From<uint32_t>(lane, x); } |
| void set_f64_bits(int lane, uint64_t x) { return From<uint64_t>(lane, x); } |
| |
| bool is_zero() const { |
| return std::all_of(std::begin(v), std::end(v), |
| [](uint8_t x) { return x == 0; }); |
| } |
| void set_zero() { std::fill(std::begin(v), std::end(v), 0); } |
| |
| template <typename T> |
| T To(int lane) const { |
| static_assert(sizeof(T) <= sizeof(v), "Invalid cast!"); |
| assert((lane + 1) * sizeof(T) <= sizeof(v)); |
| T result; |
| wabt::MemcpyEndianAware(&result, v, sizeof(result), sizeof(v), 0, |
| lane * sizeof(T), sizeof(result)); |
| return result; |
| } |
| |
| template <typename T> |
| void From(int lane, T data) { |
| static_assert(sizeof(T) <= sizeof(v), "Invalid cast!"); |
| assert((lane + 1) * sizeof(T) <= sizeof(v)); |
| wabt::MemcpyEndianAware(v, &data, sizeof(v), sizeof(data), lane * sizeof(T), |
| 0, sizeof(data)); |
| } |
| |
| uint8_t v[16]; |
| }; |
| |
| namespace wabt { |
| |
| template <typename Dst, typename Src> |
| Dst WABT_VECTORCALL Bitcast(Src&& value) { |
| static_assert(sizeof(Src) == sizeof(Dst), "Bitcast sizes must match."); |
| Dst result; |
| memcpy(&result, &value, sizeof(result)); |
| return result; |
| } |
| |
| template <typename T> |
| void ZeroMemory(T& v) { |
| WABT_STATIC_ASSERT(std::is_trivial<T>::value); |
| memset(&v, 0, sizeof(v)); |
| } |
| |
| // Placement construct |
| template <typename T, typename... Args> |
| void Construct(T& placement, Args&&... args) { |
| new (&placement) T(std::forward<Args>(args)...); |
| } |
| |
| // Placement destruct |
| template <typename T> |
| void Destruct(T& placement) { |
| placement.~T(); |
| } |
| |
| enum class LabelType { |
| Func, |
| InitExpr, |
| Block, |
| Loop, |
| If, |
| Else, |
| Try, |
| Catch, |
| |
| First = Func, |
| Last = Catch, |
| }; |
| constexpr int kLabelTypeCount = WABT_ENUM_COUNT(LabelType); |
| |
| struct Location { |
| enum class Type { |
| Text, |
| Binary, |
| }; |
| |
| Location() : line(0), first_column(0), last_column(0) {} |
| Location(std::string_view filename, |
| int line, |
| int first_column, |
| int last_column) |
| : filename(filename), |
| line(line), |
| first_column(first_column), |
| last_column(last_column) {} |
| explicit Location(size_t offset) : offset(offset) {} |
| |
| std::string_view filename; |
| union { |
| // For text files. |
| struct { |
| int line; |
| int first_column; |
| int last_column; |
| }; |
| // For binary files. |
| struct { |
| size_t offset; |
| }; |
| }; |
| }; |
| |
| enum class SegmentKind { |
| Active, |
| Passive, |
| Declared, |
| }; |
| |
| // Used in test asserts for special expected values "nan:canonical" and |
| // "nan:arithmetic" |
| enum class ExpectedNan { |
| None, |
| Canonical, |
| Arithmetic, |
| }; |
| |
| // Matches binary format, do not change. |
| enum SegmentFlags : uint8_t { |
| SegFlagsNone = 0, |
| SegPassive = 1, // bit 0: Is passive |
| SegExplicitIndex = 2, // bit 1: Has explict index (Implies table 0 if absent) |
| SegDeclared = 3, // Only used for declared segments |
| SegUseElemExprs = 4, // bit 2: Is elemexpr (Or else index sequence) |
| |
| SegFlagMax = (SegUseElemExprs << 1) - 1, // All bits set. |
| }; |
| |
| enum class RelocType { |
| FuncIndexLEB = 0, // e.g. Immediate of call instruction |
| TableIndexSLEB = 1, // e.g. Loading address of function |
| TableIndexI32 = 2, // e.g. Function address in DATA |
| MemoryAddressLEB = 3, // e.g. Memory address in load/store offset immediate |
| MemoryAddressSLEB = 4, // e.g. Memory address in i32.const |
| MemoryAddressI32 = 5, // e.g. Memory address in DATA |
| TypeIndexLEB = 6, // e.g. Immediate type in call_indirect |
| GlobalIndexLEB = 7, // e.g. Immediate of global.get inst |
| FunctionOffsetI32 = 8, // e.g. Code offset in DWARF metadata |
| SectionOffsetI32 = 9, // e.g. Section offset in DWARF metadata |
| TagIndexLEB = 10, // Used in throw instructions |
| MemoryAddressRelSLEB = 11, // In PIC code, addr relative to __memory_base |
| TableIndexRelSLEB = 12, // In PIC code, table index relative to __table_base |
| GlobalIndexI32 = 13, // e.g. Global index in data (e.g. DWARF) |
| MemoryAddressLEB64 = 14, // Memory64: Like MemoryAddressLEB |
| MemoryAddressSLEB64 = 15, // Memory64: Like MemoryAddressSLEB |
| MemoryAddressI64 = 16, // Memory64: Like MemoryAddressI32 |
| MemoryAddressRelSLEB64 = 17, // Memory64: Like MemoryAddressRelSLEB |
| TableIndexSLEB64 = 18, // Memory64: Like TableIndexSLEB |
| TableIndexI64 = 19, // Memory64: Like TableIndexI32 |
| TableNumberLEB = 20, // e.g. Immediate of table.get |
| MemoryAddressTLSSLEB = 21, // Address relative to __tls_base |
| MemoryAddressTLSI32 = 22, // Address relative to __tls_base |
| |
| First = FuncIndexLEB, |
| Last = MemoryAddressTLSI32, |
| }; |
| constexpr int kRelocTypeCount = WABT_ENUM_COUNT(RelocType); |
| |
| struct Reloc { |
| Reloc(RelocType, size_t offset, Index index, int32_t addend = 0); |
| |
| RelocType type; |
| size_t offset; |
| Index index; |
| int32_t addend; |
| }; |
| |
| enum class LinkingEntryType { |
| SegmentInfo = 5, |
| InitFunctions = 6, |
| ComdatInfo = 7, |
| SymbolTable = 8, |
| }; |
| |
| enum class DylinkEntryType { |
| MemInfo = 1, |
| Needed = 2, |
| ExportInfo = 3, |
| ImportInfo = 4, |
| }; |
| |
| enum class SymbolType { |
| Function = 0, |
| Data = 1, |
| Global = 2, |
| Section = 3, |
| Tag = 4, |
| Table = 5, |
| }; |
| |
| enum class ComdatType { |
| Data = 0x0, |
| Function = 0x1, |
| }; |
| |
| #define WABT_SYMBOL_MASK_VISIBILITY 0x4 |
| #define WABT_SYMBOL_MASK_BINDING 0x3 |
| #define WABT_SYMBOL_FLAG_UNDEFINED 0x10 |
| #define WABT_SYMBOL_FLAG_EXPORTED 0x20 |
| #define WABT_SYMBOL_FLAG_EXPLICIT_NAME 0x40 |
| #define WABT_SYMBOL_FLAG_NO_STRIP 0x80 |
| #define WABT_SYMBOL_FLAG_TLS 0x100 |
| #define WABT_SYMBOL_FLAG_ABS 0x200 |
| #define WABT_SYMBOL_FLAG_MAX 0x3ff |
| |
| #define WABT_SEGMENT_FLAG_STRINGS 0x1 |
| #define WABT_SEGMENT_FLAG_TLS 0x2 |
| #define WASM_SEGMENT_FLAG_RETAIN 0x4 |
| #define WABT_SEGMENT_FLAG_MAX 0xff |
| |
| enum class SymbolVisibility { |
| Default = 0, |
| Hidden = 4, |
| }; |
| |
| enum class SymbolBinding { |
| Global = 0, |
| Weak = 1, |
| Local = 2, |
| }; |
| |
| /* matches binary format, do not change */ |
| enum class ExternalKind { |
| Func = 0, |
| Table = 1, |
| Memory = 2, |
| Global = 3, |
| Tag = 4, |
| |
| First = Func, |
| Last = Tag, |
| }; |
| constexpr int kExternalKindCount = WABT_ENUM_COUNT(ExternalKind); |
| |
| struct Limits { |
| Limits() = default; |
| explicit Limits(uint64_t initial) : initial(initial) {} |
| Limits(uint64_t initial, uint64_t max) |
| : initial(initial), max(max), has_max(true) {} |
| Limits(uint64_t initial, uint64_t max, bool is_shared) |
| : initial(initial), max(max), has_max(true), is_shared(is_shared) {} |
| Limits(uint64_t initial, uint64_t max, bool is_shared, bool is_64) |
| : initial(initial), |
| max(max), |
| has_max(true), |
| is_shared(is_shared), |
| is_64(is_64) {} |
| Type IndexType() const { return is_64 ? Type::I64 : Type::I32; } |
| |
| uint64_t initial = 0; |
| uint64_t max = 0; |
| bool has_max = false; |
| bool is_shared = false; |
| bool is_64 = false; |
| }; |
| |
| enum { WABT_USE_NATURAL_ALIGNMENT = 0xFFFFFFFFFFFFFFFF }; |
| |
| Result ReadFile(std::string_view filename, std::vector<uint8_t>* out_data); |
| |
| void InitStdio(); |
| |
| /* external kind */ |
| |
| extern const char* g_kind_name[]; |
| |
| static inline const char* GetKindName(ExternalKind kind) { |
| return static_cast<size_t>(kind) < kExternalKindCount |
| ? g_kind_name[static_cast<size_t>(kind)] |
| : "<error_kind>"; |
| } |
| |
| /* reloc */ |
| |
| extern const char* g_reloc_type_name[]; |
| |
| static inline const char* GetRelocTypeName(RelocType reloc) { |
| return static_cast<size_t>(reloc) < kRelocTypeCount |
| ? g_reloc_type_name[static_cast<size_t>(reloc)] |
| : "<error_reloc_type>"; |
| } |
| |
| /* symbol */ |
| |
| static inline const char* GetSymbolTypeName(SymbolType type) { |
| switch (type) { |
| case SymbolType::Function: |
| return "func"; |
| case SymbolType::Global: |
| return "global"; |
| case SymbolType::Data: |
| return "data"; |
| case SymbolType::Section: |
| return "section"; |
| case SymbolType::Tag: |
| return "tag"; |
| case SymbolType::Table: |
| return "table"; |
| default: |
| return "<error_symbol_type>"; |
| } |
| } |
| |
| template <typename T> |
| void ConvertBackslashToSlash(T begin, T end) { |
| std::replace(begin, end, '\\', '/'); |
| } |
| |
| inline void ConvertBackslashToSlash(char* s, size_t length) { |
| ConvertBackslashToSlash(s, s + length); |
| } |
| |
| inline void ConvertBackslashToSlash(char* s) { |
| ConvertBackslashToSlash(s, strlen(s)); |
| } |
| |
| inline void ConvertBackslashToSlash(std::string* s) { |
| ConvertBackslashToSlash(s->begin(), s->end()); |
| } |
| |
| inline void SwapBytesSized(void* addr, size_t size) { |
| auto bytes = static_cast<uint8_t*>(addr); |
| for (size_t i = 0; i < size / 2; i++) { |
| std::swap(bytes[i], bytes[size - 1 - i]); |
| } |
| } |
| |
| } // namespace wabt |
| |
| #endif // WABT_COMMON_H_ |