Source code
Revision control
Copy as Markdown
Other Tools
/*
* 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
*
*
* 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_pod<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_MAX 0x1ff
#define WABT_SEGMENT_FLAG_STRINGS 0x1
#define WABT_SEGMENT_FLAG_TLS 0x2
#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_