blob: 3152e287850ea98066ab18a425317fbade2e46fc [file] [edit]
/*
* 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 <type_traits>
#include <vector>
#include "config.h"
#include "src/make-unique.h"
#include "src/result.h"
#include "src/string-view.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)
#define WABT_PAGE_SIZE 0x10000 /* 64k */
#define WABT_MAX_PAGES 0x10000 /* # of pages that fit in 32-bit address space \
*/
#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 PRIstringview "%.*s"
#define WABT_PRINTF_STRING_VIEW_ARG(x) \
static_cast<int>((x).length()), (x).data()
#define PRItypecode "%s%#x"
#define WABT_PRINTF_TYPE_CODE(x) \
(static_cast<int32_t>(x) < 0 ? "-" : ""), std::abs(static_cast<int32_t>(x))
#define WABT_DEFAULT_SNPRINTF_ALLOCA_BUFSIZE 128
#define WABT_SNPRINTF_ALLOCA(buffer, len, format) \
va_list args; \
va_list args_copy; \
va_start(args, format); \
va_copy(args_copy, args); \
char fixed_buf[WABT_DEFAULT_SNPRINTF_ALLOCA_BUFSIZE]; \
char* buffer = fixed_buf; \
size_t len = wabt_vsnprintf(fixed_buf, sizeof(fixed_buf), format, args); \
va_end(args); \
if (len + 1 > sizeof(fixed_buf)) { \
buffer = static_cast<char*>(alloca(len + 1)); \
len = wabt_vsnprintf(buffer, len + 1, format, args_copy); \
} \
va_end(args_copy)
#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 "u"
#define PRIoffset PRIzx
struct v128 {
uint32_t v[4];
bool operator==(const v128& other) const {
return v[0] == other.v[0] &&
v[1] == other.v[1] &&
v[2] == other.v[2] &&
v[3] == other.v[3];
}
bool operator!=(const v128& other) const { return !(*this == other); }
};
namespace wabt {
typedef uint32_t Index; // An index into one of the many index spaces.
typedef uint32_t Address; // An address or size in linear memory.
typedef size_t Offset; // An offset into a host's file or memory buffer.
static const Address kInvalidAddress = ~0;
static const Index kInvalidIndex = ~0;
static const Offset kInvalidOffset = ~0;
template <typename Dst, typename Src>
Dst 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();
}
inline std::string WABT_PRINTF_FORMAT(1, 2)
StringPrintf(const char* format, ...) {
va_list args;
va_list args_copy;
va_start(args, format);
va_copy(args_copy, args);
size_t len = wabt_vsnprintf(nullptr, 0, format, args) + 1; // For \0.
std::vector<char> buffer(len);
va_end(args);
wabt_vsnprintf(buffer.data(), len, format, args_copy);
va_end(args_copy);
return std::string(buffer.data(), len - 1);
}
enum class LabelType {
Func,
Block,
Loop,
If,
Else,
Try,
Catch,
First = Func,
Last = Catch,
};
static const int kLabelTypeCount = WABT_ENUM_COUNT(LabelType);
struct Location {
enum class Type {
Text,
Binary,
};
Location() : line(0), first_column(0), last_column(0) {}
Location(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) {}
string_view filename;
union {
// For text files.
struct {
int line;
int first_column;
int last_column;
};
// For binary files.
struct {
size_t offset;
};
};
};
// Matches binary format, do not change.
enum class Type : int32_t {
I32 = -0x01, // 0x7f
I64 = -0x02, // 0x7e
F32 = -0x03, // 0x7d
F64 = -0x04, // 0x7c
V128 = -0x05, // 0x7b
Funcref = -0x10, // 0x70
Anyref = -0x11, // 0x6f
Exnref = -0x18, // 0x68
Func = -0x20, // 0x60
Void = -0x40, // 0x40
___ = Void, // Convenient for the opcode table in opcode.h
Any = 0, // Not actually specified, but useful for type-checking
Nullref = 1, // Not actually specified, but used in testing and type-checking
Hostref = 2, // Not actually specified, but used in testing and type-checking
};
typedef std::vector<Type> TypeVector;
// Matches binary format, do not change.
enum SegmentFlags : uint8_t {
SegIndexZero = 0,
SegPassive = 1,
SegIndexOther = 2,
SegFlagMax = SegIndexOther,
};
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 get_global inst
FunctionOffsetI32 = 8, // e.g. Code offset in DWARF metadata
SectionOffsetI32 = 9, // e.g. Section offset in DWARF metadata
EventIndexLEB = 10, // Used in throw instructions
MemoryAddressRelSLEB = 11, // In PIC code, data address relative to __memory_base
TableIndexRelSLEB = 12, // In PIC code, table index relative to __table_base
First = FuncIndexLEB,
Last = TableIndexRelSLEB,
};
static const 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 SymbolType {
Function = 0,
Data = 1,
Global = 2,
Section = 3,
Event = 4,
};
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_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,
Event = 4,
First = Func,
Last = Event,
};
static const 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) {}
uint64_t initial = 0;
uint64_t max = 0;
bool has_max = false;
bool is_shared = false;
};
enum { WABT_USE_NATURAL_ALIGNMENT = 0xFFFFFFFF };
Result ReadFile(string_view filename, std::vector<uint8_t>* out_data);
void InitStdio();
/* external kind */
extern const char* g_kind_name[];
static WABT_INLINE const char* GetKindName(ExternalKind kind) {
return static_cast<int>(kind) < kExternalKindCount
? g_kind_name[static_cast<size_t>(kind)]
: "<error_kind>";
}
/* reloc */
extern const char* g_reloc_type_name[];
static WABT_INLINE const char* GetRelocTypeName(RelocType reloc) {
return static_cast<int>(reloc) < kRelocTypeCount
? g_reloc_type_name[static_cast<size_t>(reloc)]
: "<error_reloc_type>";
}
/* symbol */
static WABT_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::Event:
return "event";
default:
return "<error_symbol_type>";
}
}
/* type */
static WABT_INLINE const char* GetTypeName(Type type) {
switch (type) {
case Type::I32:
return "i32";
case Type::I64:
return "i64";
case Type::F32:
return "f32";
case Type::F64:
return "f64";
case Type::V128:
return "v128";
case Type::Funcref:
return "funcref";
case Type::Func:
return "func";
case Type::Exnref:
return "exnref";
case Type::Void:
return "void";
case Type::Any:
return "any";
case Type::Anyref:
return "anyref";
case Type::Nullref:
return "nullref";
default:
return "<type_index>";
}
}
static WABT_INLINE bool IsTypeIndex(Type type) {
return static_cast<int32_t>(type) >= 0;
}
static WABT_INLINE Index GetTypeIndex(Type type) {
assert(IsTypeIndex(type));
return static_cast<Index>(type);
}
static WABT_INLINE TypeVector GetInlineTypeVector(Type type) {
assert(!IsTypeIndex(type));
switch (type) {
case Type::Void:
return TypeVector();
case Type::I32:
case Type::I64:
case Type::F32:
case Type::F64:
case Type::V128:
case Type::Funcref:
case Type::Anyref:
case Type::Exnref:
return TypeVector(&type, &type + 1);
default:
WABT_UNREACHABLE;
}
}
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());
}
} // namespace wabt
#endif // WABT_COMMON_H_