#ifndef wasm_wasm_h
#define wasm_wasm_h
#include <algorithm>
#include <array>
#include <cassert>
#include <map>
#include <ostream>
#include <string>
#include <unordered_map>
#include <vector>
#include "literal.h"
#include "mixed_arena.h"
#include "support/index.h"
#include "support/name.h"
#include "wasm-features.h"
#include "wasm-type.h"
namespace wasm {
class Module;
using Index = uint32_t;
struct Address {
using address32_t = uint32_t;
using address64_t = uint64_t;
address64_t addr;
constexpr Address() : addr(0) {}
constexpr Address(uint64_t a) : addr(a) {}
Address& operator=(uint64_t a) {
addr = a;
return *this;
}
operator address64_t() const { return addr; }
Address& operator++(int) {
++addr;
return *this;
}
};
enum class IRProfile { Normal, Poppy };
enum UnaryOp {
ClzInt32,
ClzInt64,
CtzInt32,
CtzInt64,
PopcntInt32,
PopcntInt64,
NegFloat32,
NegFloat64,
AbsFloat32,
AbsFloat64,
CeilFloat32,
CeilFloat64,
FloorFloat32,
FloorFloat64,
TruncFloat32,
TruncFloat64,
NearestFloat32,
NearestFloat64,
SqrtFloat32,
SqrtFloat64,
EqZInt32,
EqZInt64,
ExtendSInt32,
ExtendUInt32,
WrapInt64,
TruncSFloat32ToInt32,
TruncSFloat32ToInt64,
TruncUFloat32ToInt32,
TruncUFloat32ToInt64,
TruncSFloat64ToInt32,
TruncSFloat64ToInt64,
TruncUFloat64ToInt32,
TruncUFloat64ToInt64,
ReinterpretFloat32,
ReinterpretFloat64,
ConvertSInt32ToFloat32,
ConvertSInt32ToFloat64,
ConvertUInt32ToFloat32,
ConvertUInt32ToFloat64,
ConvertSInt64ToFloat32,
ConvertSInt64ToFloat64,
ConvertUInt64ToFloat32,
ConvertUInt64ToFloat64,
PromoteFloat32,
DemoteFloat64,
ReinterpretInt32,
ReinterpretInt64,
ExtendS8Int32,
ExtendS16Int32,
ExtendS8Int64,
ExtendS16Int64,
ExtendS32Int64,
TruncSatSFloat32ToInt32,
TruncSatUFloat32ToInt32,
TruncSatSFloat64ToInt32,
TruncSatUFloat64ToInt32,
TruncSatSFloat32ToInt64,
TruncSatUFloat32ToInt64,
TruncSatSFloat64ToInt64,
TruncSatUFloat64ToInt64,
SplatVecI8x16,
SplatVecI16x8,
SplatVecI32x4,
SplatVecI64x2,
SplatVecF32x4,
SplatVecF64x2,
NotVec128,
AnyTrueVec128,
AbsVecI8x16,
NegVecI8x16,
AllTrueVecI8x16,
BitmaskVecI8x16,
PopcntVecI8x16,
AbsVecI16x8,
NegVecI16x8,
AllTrueVecI16x8,
BitmaskVecI16x8,
AbsVecI32x4,
NegVecI32x4,
AllTrueVecI32x4,
BitmaskVecI32x4,
AbsVecI64x2,
NegVecI64x2,
AllTrueVecI64x2,
BitmaskVecI64x2,
AbsVecF32x4,
NegVecF32x4,
SqrtVecF32x4,
CeilVecF32x4,
FloorVecF32x4,
TruncVecF32x4,
NearestVecF32x4,
AbsVecF64x2,
NegVecF64x2,
SqrtVecF64x2,
CeilVecF64x2,
FloorVecF64x2,
TruncVecF64x2,
NearestVecF64x2,
ExtAddPairwiseSVecI8x16ToI16x8,
ExtAddPairwiseUVecI8x16ToI16x8,
ExtAddPairwiseSVecI16x8ToI32x4,
ExtAddPairwiseUVecI16x8ToI32x4,
TruncSatSVecF32x4ToVecI32x4,
TruncSatUVecF32x4ToVecI32x4,
ConvertSVecI32x4ToVecF32x4,
ConvertUVecI32x4ToVecF32x4,
ExtendLowSVecI8x16ToVecI16x8,
ExtendHighSVecI8x16ToVecI16x8,
ExtendLowUVecI8x16ToVecI16x8,
ExtendHighUVecI8x16ToVecI16x8,
ExtendLowSVecI16x8ToVecI32x4,
ExtendHighSVecI16x8ToVecI32x4,
ExtendLowUVecI16x8ToVecI32x4,
ExtendHighUVecI16x8ToVecI32x4,
ExtendLowSVecI32x4ToVecI64x2,
ExtendHighSVecI32x4ToVecI64x2,
ExtendLowUVecI32x4ToVecI64x2,
ExtendHighUVecI32x4ToVecI64x2,
ConvertLowSVecI32x4ToVecF64x2,
ConvertLowUVecI32x4ToVecF64x2,
TruncSatZeroSVecF64x2ToVecI32x4,
TruncSatZeroUVecF64x2ToVecI32x4,
DemoteZeroVecF64x2ToVecF32x4,
PromoteLowVecF32x4ToVecF64x2,
RelaxedTruncSVecF32x4ToVecI32x4,
RelaxedTruncUVecF32x4ToVecI32x4,
RelaxedTruncZeroSVecF64x2ToVecI32x4,
RelaxedTruncZeroUVecF64x2ToVecI32x4,
InvalidUnary
};
enum BinaryOp {
AddInt32,
SubInt32,
MulInt32,
DivSInt32,
DivUInt32,
RemSInt32,
RemUInt32,
AndInt32,
OrInt32,
XorInt32,
ShlInt32,
ShrSInt32,
ShrUInt32,
RotLInt32,
RotRInt32,
EqInt32,
NeInt32,
LtSInt32,
LtUInt32,
LeSInt32,
LeUInt32,
GtSInt32,
GtUInt32,
GeSInt32,
GeUInt32,
AddInt64,
SubInt64,
MulInt64,
DivSInt64,
DivUInt64,
RemSInt64,
RemUInt64,
AndInt64,
OrInt64,
XorInt64,
ShlInt64,
ShrSInt64,
ShrUInt64,
RotLInt64,
RotRInt64,
EqInt64,
NeInt64,
LtSInt64,
LtUInt64,
LeSInt64,
LeUInt64,
GtSInt64,
GtUInt64,
GeSInt64,
GeUInt64,
AddFloat32,
SubFloat32,
MulFloat32,
DivFloat32,
CopySignFloat32,
MinFloat32,
MaxFloat32,
EqFloat32,
NeFloat32,
LtFloat32,
LeFloat32,
GtFloat32,
GeFloat32,
AddFloat64,
SubFloat64,
MulFloat64,
DivFloat64,
CopySignFloat64,
MinFloat64,
MaxFloat64,
EqFloat64,
NeFloat64,
LtFloat64,
LeFloat64,
GtFloat64,
GeFloat64,
EqVecI8x16,
NeVecI8x16,
LtSVecI8x16,
LtUVecI8x16,
GtSVecI8x16,
GtUVecI8x16,
LeSVecI8x16,
LeUVecI8x16,
GeSVecI8x16,
GeUVecI8x16,
EqVecI16x8,
NeVecI16x8,
LtSVecI16x8,
LtUVecI16x8,
GtSVecI16x8,
GtUVecI16x8,
LeSVecI16x8,
LeUVecI16x8,
GeSVecI16x8,
GeUVecI16x8,
EqVecI32x4,
NeVecI32x4,
LtSVecI32x4,
LtUVecI32x4,
GtSVecI32x4,
GtUVecI32x4,
LeSVecI32x4,
LeUVecI32x4,
GeSVecI32x4,
GeUVecI32x4,
EqVecI64x2,
NeVecI64x2,
LtSVecI64x2,
GtSVecI64x2,
LeSVecI64x2,
GeSVecI64x2,
EqVecF32x4,
NeVecF32x4,
LtVecF32x4,
GtVecF32x4,
LeVecF32x4,
GeVecF32x4,
EqVecF64x2,
NeVecF64x2,
LtVecF64x2,
GtVecF64x2,
LeVecF64x2,
GeVecF64x2,
AndVec128,
OrVec128,
XorVec128,
AndNotVec128,
AddVecI8x16,
AddSatSVecI8x16,
AddSatUVecI8x16,
SubVecI8x16,
SubSatSVecI8x16,
SubSatUVecI8x16,
MinSVecI8x16,
MinUVecI8x16,
MaxSVecI8x16,
MaxUVecI8x16,
AvgrUVecI8x16,
AddVecI16x8,
AddSatSVecI16x8,
AddSatUVecI16x8,
SubVecI16x8,
SubSatSVecI16x8,
SubSatUVecI16x8,
MulVecI16x8,
MinSVecI16x8,
MinUVecI16x8,
MaxSVecI16x8,
MaxUVecI16x8,
AvgrUVecI16x8,
Q15MulrSatSVecI16x8,
ExtMulLowSVecI16x8,
ExtMulHighSVecI16x8,
ExtMulLowUVecI16x8,
ExtMulHighUVecI16x8,
AddVecI32x4,
SubVecI32x4,
MulVecI32x4,
MinSVecI32x4,
MinUVecI32x4,
MaxSVecI32x4,
MaxUVecI32x4,
DotSVecI16x8ToVecI32x4,
ExtMulLowSVecI32x4,
ExtMulHighSVecI32x4,
ExtMulLowUVecI32x4,
ExtMulHighUVecI32x4,
AddVecI64x2,
SubVecI64x2,
MulVecI64x2,
ExtMulLowSVecI64x2,
ExtMulHighSVecI64x2,
ExtMulLowUVecI64x2,
ExtMulHighUVecI64x2,
AddVecF32x4,
SubVecF32x4,
MulVecF32x4,
DivVecF32x4,
MinVecF32x4,
MaxVecF32x4,
PMinVecF32x4,
PMaxVecF32x4,
AddVecF64x2,
SubVecF64x2,
MulVecF64x2,
DivVecF64x2,
MinVecF64x2,
MaxVecF64x2,
PMinVecF64x2,
PMaxVecF64x2,
NarrowSVecI16x8ToVecI8x16,
NarrowUVecI16x8ToVecI8x16,
NarrowSVecI32x4ToVecI16x8,
NarrowUVecI32x4ToVecI16x8,
SwizzleVecI8x16,
RelaxedSwizzleVecI8x16,
RelaxedMinVecF32x4,
RelaxedMaxVecF32x4,
RelaxedMinVecF64x2,
RelaxedMaxVecF64x2,
RelaxedQ15MulrSVecI16x8,
DotI8x16I7x16SToVecI16x8,
InvalidBinary
};
enum AtomicRMWOp { RMWAdd, RMWSub, RMWAnd, RMWOr, RMWXor, RMWXchg };
enum SIMDExtractOp {
ExtractLaneSVecI8x16,
ExtractLaneUVecI8x16,
ExtractLaneSVecI16x8,
ExtractLaneUVecI16x8,
ExtractLaneVecI32x4,
ExtractLaneVecI64x2,
ExtractLaneVecF32x4,
ExtractLaneVecF64x2
};
enum SIMDReplaceOp {
ReplaceLaneVecI8x16,
ReplaceLaneVecI16x8,
ReplaceLaneVecI32x4,
ReplaceLaneVecI64x2,
ReplaceLaneVecF32x4,
ReplaceLaneVecF64x2,
};
enum SIMDShiftOp {
ShlVecI8x16,
ShrSVecI8x16,
ShrUVecI8x16,
ShlVecI16x8,
ShrSVecI16x8,
ShrUVecI16x8,
ShlVecI32x4,
ShrSVecI32x4,
ShrUVecI32x4,
ShlVecI64x2,
ShrSVecI64x2,
ShrUVecI64x2
};
enum SIMDLoadOp {
Load8SplatVec128,
Load16SplatVec128,
Load32SplatVec128,
Load64SplatVec128,
Load8x8SVec128,
Load8x8UVec128,
Load16x4SVec128,
Load16x4UVec128,
Load32x2SVec128,
Load32x2UVec128,
Load32ZeroVec128,
Load64ZeroVec128,
};
enum SIMDLoadStoreLaneOp {
Load8LaneVec128,
Load16LaneVec128,
Load32LaneVec128,
Load64LaneVec128,
Store8LaneVec128,
Store16LaneVec128,
Store32LaneVec128,
Store64LaneVec128,
};
enum SIMDTernaryOp {
Bitselect,
RelaxedFmaVecF32x4,
RelaxedFmsVecF32x4,
RelaxedFmaVecF64x2,
RelaxedFmsVecF64x2,
LaneselectI8x16,
LaneselectI16x8,
LaneselectI32x4,
LaneselectI64x2,
DotI8x16I7x16AddSToVecI32x4,
};
enum RefAsOp {
RefAsNonNull,
ExternInternalize,
ExternExternalize,
};
enum BrOnOp {
BrOnNull,
BrOnNonNull,
BrOnCast,
BrOnCastFail,
};
enum StringNewOp {
StringNewUTF8,
StringNewWTF8,
StringNewLossyUTF8,
StringNewWTF16,
StringNewUTF8Array,
StringNewWTF8Array,
StringNewLossyUTF8Array,
StringNewWTF16Array,
StringNewFromCodePoint,
};
enum StringMeasureOp {
StringMeasureUTF8,
StringMeasureWTF8,
StringMeasureWTF16,
StringMeasureIsUSV,
StringMeasureWTF16View,
StringMeasureHash,
};
enum StringEncodeOp {
StringEncodeUTF8,
StringEncodeLossyUTF8,
StringEncodeWTF8,
StringEncodeWTF16,
StringEncodeUTF8Array,
StringEncodeLossyUTF8Array,
StringEncodeWTF8Array,
StringEncodeWTF16Array,
};
enum StringEqOp {
StringEqEqual,
StringEqCompare,
};
enum StringAsOp {
StringAsWTF8,
StringAsWTF16,
StringAsIter,
};
enum StringIterMoveOp {
StringIterMoveAdvance,
StringIterMoveRewind,
};
enum StringSliceWTFOp {
StringSliceWTF8,
StringSliceWTF16,
};
class Expression {
public:
enum Id {
InvalidId = 0,
BlockId,
IfId,
LoopId,
BreakId,
SwitchId,
CallId,
CallIndirectId,
LocalGetId,
LocalSetId,
GlobalGetId,
GlobalSetId,
LoadId,
StoreId,
ConstId,
UnaryId,
BinaryId,
SelectId,
DropId,
ReturnId,
MemorySizeId,
MemoryGrowId,
NopId,
UnreachableId,
AtomicRMWId,
AtomicCmpxchgId,
AtomicWaitId,
AtomicNotifyId,
AtomicFenceId,
SIMDExtractId,
SIMDReplaceId,
SIMDShuffleId,
SIMDTernaryId,
SIMDShiftId,
SIMDLoadId,
SIMDLoadStoreLaneId,
MemoryInitId,
DataDropId,
MemoryCopyId,
MemoryFillId,
PopId,
RefNullId,
RefIsNullId,
RefFuncId,
RefEqId,
TableGetId,
TableSetId,
TableSizeId,
TableGrowId,
TableFillId,
TableCopyId,
TryId,
TryTableId,
ThrowId,
RethrowId,
ThrowRefId,
TupleMakeId,
TupleExtractId,
RefI31Id,
I31GetId,
CallRefId,
RefTestId,
RefCastId,
BrOnId,
StructNewId,
StructGetId,
StructSetId,
ArrayNewId,
ArrayNewDataId,
ArrayNewElemId,
ArrayNewFixedId,
ArrayGetId,
ArraySetId,
ArrayLenId,
ArrayCopyId,
ArrayFillId,
ArrayInitDataId,
ArrayInitElemId,
RefAsId,
StringNewId,
StringConstId,
StringMeasureId,
StringEncodeId,
StringConcatId,
StringEqId,
StringAsId,
StringWTF8AdvanceId,
StringWTF16GetId,
StringIterNextId,
StringIterMoveId,
StringSliceWTFId,
StringSliceIterId,
ContBindId,
ContNewId,
ResumeId,
NumExpressionIds
};
Id _id;
Type type = Type::none;
Expression(Id id) : _id(id) {}
protected:
Expression(const Expression& other) = default;
Expression(Expression&& other) = default;
Expression& operator=(Expression& other) = default;
Expression& operator=(Expression&& other) = default;
public:
void finalize() {}
template<class T> bool is() const {
static_assert(std::is_base_of<Expression, T>::value,
"Expression is not a base of destination type T");
return int(_id) == int(T::SpecificId);
}
template<class T> T* dynCast() {
static_assert(std::is_base_of<Expression, T>::value,
"Expression is not a base of destination type T");
return int(_id) == int(T::SpecificId) ? (T*)this : nullptr;
}
template<class T> const T* dynCast() const {
static_assert(std::is_base_of<Expression, T>::value,
"Expression is not a base of destination type T");
return int(_id) == int(T::SpecificId) ? (const T*)this : nullptr;
}
template<class T> T* cast() {
static_assert(std::is_base_of<Expression, T>::value,
"Expression is not a base of destination type T");
assert(int(_id) == int(T::SpecificId));
return (T*)this;
}
template<class T> const T* cast() const {
static_assert(std::is_base_of<Expression, T>::value,
"Expression is not a base of destination type T");
assert(int(_id) == int(T::SpecificId));
return (const T*)this;
}
void dump();
};
const char* getExpressionName(Expression* curr);
Literal getLiteralFromConstExpression(Expression* curr);
Literals getLiteralsFromConstExpression(Expression* curr);
using ExpressionList = ArenaVector<Expression*>;
template<Expression::Id SID> class SpecificExpression : public Expression {
public:
enum {
SpecificId = SID };
SpecificExpression() : Expression(SID) {}
};
class Nop : public SpecificExpression<Expression::NopId> {
public:
Nop() = default;
Nop(MixedArena& allocator) {}
};
class Block : public SpecificExpression<Expression::BlockId> {
public:
Block(MixedArena& allocator) : list(allocator) {}
Name name;
ExpressionList list;
enum Breakability { Unknown, HasBreak, NoBreak };
void finalize(std::optional<Type> type_ = std::nullopt,
Breakability breakability = Unknown);
};
class If : public SpecificExpression<Expression::IfId> {
public:
If() : ifFalse(nullptr) {}
If(MixedArena& allocator) : If() {}
Expression* condition;
Expression* ifTrue;
Expression* ifFalse;
void finalize(std::optional<Type> type_ = std::nullopt);
};
class Loop : public SpecificExpression<Expression::LoopId> {
public:
Loop() = default;
Loop(MixedArena& allocator) {}
Name name;
Expression* body;
void finalize(std::optional<Type> type_ = std::nullopt);
};
class Break : public SpecificExpression<Expression::BreakId> {
public:
Break() : value(nullptr), condition(nullptr) {}
Break(MixedArena& allocator) : Break() { type = Type::unreachable; }
Name name;
Expression* value;
Expression* condition;
void finalize();
};
class Switch : public SpecificExpression<Expression::SwitchId> {
public:
Switch(MixedArena& allocator) : targets(allocator) {
type = Type::unreachable;
}
ArenaVector<Name> targets;
Name default_;
Expression* value = nullptr;
Expression* condition = nullptr;
void finalize();
};
class Call : public SpecificExpression<Expression::CallId> {
public:
Call(MixedArena& allocator) : operands(allocator) {}
ExpressionList operands;
Name target;
bool isReturn = false;
void finalize();
};
class CallIndirect : public SpecificExpression<Expression::CallIndirectId> {
public:
CallIndirect(MixedArena& allocator) : operands(allocator) {}
HeapType heapType;
ExpressionList operands;
Expression* target;
Name table;
bool isReturn = false;
void finalize();
};
class LocalGet : public SpecificExpression<Expression::LocalGetId> {
public:
LocalGet() = default;
LocalGet(MixedArena& allocator) {}
Index index;
};
class LocalSet : public SpecificExpression<Expression::LocalSetId> {
public:
LocalSet() = default;
LocalSet(MixedArena& allocator) {}
void finalize();
Index index;
Expression* value;
bool isTee() const;
void makeTee(Type type);
void makeSet();
};
class GlobalGet : public SpecificExpression<Expression::GlobalGetId> {
public:
GlobalGet() = default;
GlobalGet(MixedArena& allocator) {}
Name name;
};
class GlobalSet : public SpecificExpression<Expression::GlobalSetId> {
public:
GlobalSet() = default;
GlobalSet(MixedArena& allocator) {}
Name name;
Expression* value;
void finalize();
};
class Load : public SpecificExpression<Expression::LoadId> {
public:
Load() = default;
Load(MixedArena& allocator) {}
uint8_t bytes;
bool signed_ = false;
Address offset;
Address align;
bool isAtomic;
Expression* ptr;
Name memory;
void finalize();
};
class Store : public SpecificExpression<Expression::StoreId> {
public:
Store() = default;
Store(MixedArena& allocator) : Store() {}
uint8_t bytes;
Address offset;
Address align;
bool isAtomic;
Expression* ptr;
Expression* value;
Type valueType;
Name memory;
void finalize();
};
class AtomicRMW : public SpecificExpression<Expression::AtomicRMWId> {
public:
AtomicRMW() = default;
AtomicRMW(MixedArena& allocator) : AtomicRMW() {}
AtomicRMWOp op;
uint8_t bytes;
Address offset;
Expression* ptr;
Expression* value;
Name memory;
void finalize();
};
class AtomicCmpxchg : public SpecificExpression<Expression::AtomicCmpxchgId> {
public:
AtomicCmpxchg() = default;
AtomicCmpxchg(MixedArena& allocator) : AtomicCmpxchg() {}
uint8_t bytes;
Address offset;
Expression* ptr;
Expression* expected;
Expression* replacement;
Name memory;
void finalize();
};
class AtomicWait : public SpecificExpression<Expression::AtomicWaitId> {
public:
AtomicWait() = default;
AtomicWait(MixedArena& allocator) : AtomicWait() {}
Address offset;
Expression* ptr;
Expression* expected;
Expression* timeout;
Type expectedType;
Name memory;
void finalize();
};
class AtomicNotify : public SpecificExpression<Expression::AtomicNotifyId> {
public:
AtomicNotify() = default;
AtomicNotify(MixedArena& allocator) : AtomicNotify() {}
Address offset;
Expression* ptr;
Expression* notifyCount;
Name memory;
void finalize();
};
class AtomicFence : public SpecificExpression<Expression::AtomicFenceId> {
public:
AtomicFence() = default;
AtomicFence(MixedArena& allocator) : AtomicFence() {}
uint8_t order = 0;
void finalize();
};
class SIMDExtract : public SpecificExpression<Expression::SIMDExtractId> {
public:
SIMDExtract() = default;
SIMDExtract(MixedArena& allocator) : SIMDExtract() {}
SIMDExtractOp op;
Expression* vec;
uint8_t index;
void finalize();
};
class SIMDReplace : public SpecificExpression<Expression::SIMDReplaceId> {
public:
SIMDReplace() = default;
SIMDReplace(MixedArena& allocator) : SIMDReplace() {}
SIMDReplaceOp op;
Expression* vec;
uint8_t index;
Expression* value;
void finalize();
};
class SIMDShuffle : public SpecificExpression<Expression::SIMDShuffleId> {
public:
SIMDShuffle() = default;
SIMDShuffle(MixedArena& allocator) : SIMDShuffle() {}
Expression* left;
Expression* right;
std::array<uint8_t, 16> mask;
void finalize();
};
class SIMDTernary : public SpecificExpression<Expression::SIMDTernaryId> {
public:
SIMDTernary() = default;
SIMDTernary(MixedArena& allocator) : SIMDTernary() {}
SIMDTernaryOp op;
Expression* a;
Expression* b;
Expression* c;
void finalize();
};
class SIMDShift : public SpecificExpression<Expression::SIMDShiftId> {
public:
SIMDShift() = default;
SIMDShift(MixedArena& allocator) : SIMDShift() {}
SIMDShiftOp op;
Expression* vec;
Expression* shift;
void finalize();
};
class SIMDLoad : public SpecificExpression<Expression::SIMDLoadId> {
public:
SIMDLoad() = default;
SIMDLoad(MixedArena& allocator) {}
SIMDLoadOp op;
Address offset;
Address align;
Expression* ptr;
Name memory;
Index getMemBytes();
void finalize();
};
class SIMDLoadStoreLane
: public SpecificExpression<Expression::SIMDLoadStoreLaneId> {
public:
SIMDLoadStoreLane() = default;
SIMDLoadStoreLane(MixedArena& allocator) {}
SIMDLoadStoreLaneOp op;
Address offset;
Address align;
uint8_t index;
Expression* ptr;
Expression* vec;
Name memory;
bool isStore();
bool isLoad() { return !isStore(); }
Index getMemBytes();
void finalize();
};
class MemoryInit : public SpecificExpression<Expression::MemoryInitId> {
public:
MemoryInit() = default;
MemoryInit(MixedArena& allocator) : MemoryInit() {}
Name segment;
Expression* dest;
Expression* offset;
Expression* size;
Name memory;
void finalize();
};
class DataDrop : public SpecificExpression<Expression::DataDropId> {
public:
DataDrop() = default;
DataDrop(MixedArena& allocator) : DataDrop() {}
Name segment;
void finalize();
};
class MemoryCopy : public SpecificExpression<Expression::MemoryCopyId> {
public:
MemoryCopy() = default;
MemoryCopy(MixedArena& allocator) : MemoryCopy() {}
Expression* dest;
Expression* source;
Expression* size;
Name destMemory;
Name sourceMemory;
void finalize();
};
class MemoryFill : public SpecificExpression<Expression::MemoryFillId> {
public:
MemoryFill() = default;
MemoryFill(MixedArena& allocator) : MemoryFill() {}
Expression* dest;
Expression* value;
Expression* size;
Name memory;
void finalize();
};
class Const : public SpecificExpression<Expression::ConstId> {
public:
Const() = default;
Const(MixedArena& allocator) {}
Literal value;
Const* set(Literal value_);
void finalize();
};
class Unary : public SpecificExpression<Expression::UnaryId> {
public:
Unary() = default;
Unary(MixedArena& allocator) {}
UnaryOp op;
Expression* value;
bool isRelational();
void finalize();
};
class Binary : public SpecificExpression<Expression::BinaryId> {
public:
Binary() = default;
Binary(MixedArena& allocator) {}
BinaryOp op;
Expression* left;
Expression* right;
bool isRelational();
void finalize();
};
class Select : public SpecificExpression<Expression::SelectId> {
public:
Select() = default;
Select(MixedArena& allocator) {}
Expression* ifTrue;
Expression* ifFalse;
Expression* condition;
void finalize();
void finalize(Type type_);
};
class Drop : public SpecificExpression<Expression::DropId> {
public:
Drop() = default;
Drop(MixedArena& allocator) {}
Expression* value;
void finalize();
};
class Return : public SpecificExpression<Expression::ReturnId> {
public:
Return() { type = Type::unreachable; }
Return(MixedArena& allocator) : Return() {}
Expression* value = nullptr;
};
class MemorySize : public SpecificExpression<Expression::MemorySizeId> {
public:
MemorySize() { type = Type::i32; }
MemorySize(MixedArena& allocator) : MemorySize() {}
Type ptrType = Type::i32;
Name memory;
void make64();
void finalize();
};
class MemoryGrow : public SpecificExpression<Expression::MemoryGrowId> {
public:
MemoryGrow() { type = Type::i32; }
MemoryGrow(MixedArena& allocator) : MemoryGrow() {}
Expression* delta = nullptr;
Type ptrType = Type::i32;
Name memory;
void make64();
void finalize();
};
class Unreachable : public SpecificExpression<Expression::UnreachableId> {
public:
Unreachable() { type = Type::unreachable; }
Unreachable(MixedArena& allocator) : Unreachable() {}
};
class Pop : public SpecificExpression<Expression::PopId> {
public:
Pop() = default;
Pop(MixedArena& allocator) {}
};
class RefNull : public SpecificExpression<Expression::RefNullId> {
public:
RefNull() = default;
RefNull(MixedArena& allocator) {}
void finalize();
void finalize(HeapType heapType);
void finalize(Type type);
};
class RefIsNull : public SpecificExpression<Expression::RefIsNullId> {
public:
RefIsNull() = default;
RefIsNull(MixedArena& allocator) {}
Expression* value;
void finalize();
};
class RefFunc : public SpecificExpression<Expression::RefFuncId> {
public:
RefFunc(MixedArena& allocator) {}
Name func;
void finalize();
void finalize(Type type_);
};
class RefEq : public SpecificExpression<Expression::RefEqId> {
public:
RefEq() = default;
RefEq(MixedArena& allocator) {}
Expression* left;
Expression* right;
void finalize();
};
class TableGet : public SpecificExpression<Expression::TableGetId> {
public:
TableGet() = default;
TableGet(MixedArena& allocator) {}
Name table;
Expression* index;
void finalize();
};
class TableSet : public SpecificExpression<Expression::TableSetId> {
public:
TableSet() = default;
TableSet(MixedArena& allocator) {}
Name table;
Expression* index;
Expression* value;
void finalize();
};
class TableSize : public SpecificExpression<Expression::TableSizeId> {
public:
TableSize() { type = Type::i32; }
TableSize(MixedArena& allocator) : TableSize() {}
Name table;
void finalize();
};
class TableGrow : public SpecificExpression<Expression::TableGrowId> {
public:
TableGrow() { type = Type::i32; }
TableGrow(MixedArena& allocator) : TableGrow() {}
Name table;
Expression* value;
Expression* delta;
void finalize();
};
class TableFill : public SpecificExpression<Expression::TableFillId> {
public:
TableFill() = default;
TableFill(MixedArena& allocator) : TableFill() {}
Name table;
Expression* dest;
Expression* value;
Expression* size;
void finalize();
};
class TableCopy : public SpecificExpression<Expression::TableCopyId> {
public:
TableCopy() = default;
TableCopy(MixedArena& allocator) : TableCopy() {}
Expression* dest;
Expression* source;
Expression* size;
Name destTable;
Name sourceTable;
void finalize();
};
class Try : public SpecificExpression<Expression::TryId> {
public:
Try(MixedArena& allocator) : catchTags(allocator), catchBodies(allocator) {}
Name name; Expression* body;
ArenaVector<Name> catchTags;
ExpressionList catchBodies;
Name delegateTarget;
bool hasCatchAll() const {
return catchBodies.size() - catchTags.size() == 1;
}
bool isCatch() const { return !catchBodies.empty(); }
bool isDelegate() const { return delegateTarget.is(); }
void finalize(std::optional<Type> type_ = std::nullopt);
};
class TryTable : public SpecificExpression<Expression::TryTableId> {
public:
TryTable(MixedArena& allocator)
: catchTags(allocator), catchDests(allocator), catchRefs(allocator),
sentTypes(allocator) {}
Expression* body;
ArenaVector<Name> catchTags;
ArenaVector<Name> catchDests;
ArenaVector<bool> catchRefs;
bool hasCatchAll() const;
void finalize(std::optional<Type> type_ = std::nullopt,
Module* wasm = nullptr);
ArenaVector<Type> sentTypes;
};
class Throw : public SpecificExpression<Expression::ThrowId> {
public:
Throw(MixedArena& allocator) : operands(allocator) {}
Name tag;
ExpressionList operands;
void finalize();
};
class Rethrow : public SpecificExpression<Expression::RethrowId> {
public:
Rethrow(MixedArena& allocator) {}
Name target;
void finalize();
};
class ThrowRef : public SpecificExpression<Expression::ThrowRefId> {
public:
ThrowRef() = default;
ThrowRef(MixedArena& allocator) {}
Expression* exnref;
void finalize();
};
class TupleMake : public SpecificExpression<Expression::TupleMakeId> {
public:
TupleMake(MixedArena& allocator) : operands(allocator) {}
ExpressionList operands;
void finalize();
};
class TupleExtract : public SpecificExpression<Expression::TupleExtractId> {
public:
TupleExtract() = default;
TupleExtract(MixedArena& allocator) {}
Expression* tuple;
Index index;
void finalize();
};
class RefI31 : public SpecificExpression<Expression::RefI31Id> {
public:
RefI31() = default;
RefI31(MixedArena& allocator) {}
Expression* value;
void finalize();
};
class I31Get : public SpecificExpression<Expression::I31GetId> {
public:
I31Get() = default;
I31Get(MixedArena& allocator) {}
Expression* i31;
bool signed_ = false;
void finalize();
};
class CallRef : public SpecificExpression<Expression::CallRefId> {
public:
CallRef(MixedArena& allocator) : operands(allocator) {}
ExpressionList operands;
Expression* target;
bool isReturn = false;
void finalize();
};
class RefTest : public SpecificExpression<Expression::RefTestId> {
public:
RefTest() = default;
RefTest(MixedArena& allocator) {}
Expression* ref;
Type castType;
void finalize();
Type& getCastType() { return castType; }
};
class RefCast : public SpecificExpression<Expression::RefCastId> {
public:
RefCast() = default;
RefCast(MixedArena& allocator) {}
Expression* ref;
void finalize();
Type& getCastType() { return type; }
};
class BrOn : public SpecificExpression<Expression::BrOnId> {
public:
BrOn() = default;
BrOn(MixedArena& allocator) {}
BrOnOp op;
Name name;
Expression* ref;
Type castType;
void finalize();
Type& getCastType() { return castType; }
Type getSentType();
};
class StructNew : public SpecificExpression<Expression::StructNewId> {
public:
StructNew(MixedArena& allocator) : operands(allocator) {}
ExpressionList operands;
bool isWithDefault() { return operands.empty(); }
void finalize();
};
class StructGet : public SpecificExpression<Expression::StructGetId> {
public:
StructGet() = default;
StructGet(MixedArena& allocator) {}
Index index;
Expression* ref;
bool signed_ = false;
void finalize();
};
class StructSet : public SpecificExpression<Expression::StructSetId> {
public:
StructSet() = default;
StructSet(MixedArena& allocator) {}
Index index;
Expression* ref;
Expression* value;
void finalize();
};
class ArrayNew : public SpecificExpression<Expression::ArrayNewId> {
public:
ArrayNew() = default;
ArrayNew(MixedArena& allocator) {}
Expression* init = nullptr;
Expression* size;
bool isWithDefault() { return !init; }
void finalize();
};
class ArrayNewData : public SpecificExpression<Expression::ArrayNewDataId> {
public:
ArrayNewData() = default;
ArrayNewData(MixedArena& allocator) {}
Name segment;
Expression* offset;
Expression* size;
void finalize();
};
class ArrayNewElem : public SpecificExpression<Expression::ArrayNewElemId> {
public:
ArrayNewElem() = default;
ArrayNewElem(MixedArena& allocator) {}
Name segment;
Expression* offset;
Expression* size;
void finalize();
};
class ArrayNewFixed : public SpecificExpression<Expression::ArrayNewFixedId> {
public:
ArrayNewFixed(MixedArena& allocator) : values(allocator) {}
ExpressionList values;
void finalize();
};
class ArrayGet : public SpecificExpression<Expression::ArrayGetId> {
public:
ArrayGet() = default;
ArrayGet(MixedArena& allocator) {}
Expression* ref;
Expression* index;
bool signed_ = false;
void finalize();
};
class ArraySet : public SpecificExpression<Expression::ArraySetId> {
public:
ArraySet() = default;
ArraySet(MixedArena& allocator) {}
Expression* ref;
Expression* index;
Expression* value;
void finalize();
};
class ArrayLen : public SpecificExpression<Expression::ArrayLenId> {
public:
ArrayLen() = default;
ArrayLen(MixedArena& allocator) {}
Expression* ref;
void finalize();
};
class ArrayCopy : public SpecificExpression<Expression::ArrayCopyId> {
public:
ArrayCopy() = default;
ArrayCopy(MixedArena& allocator) {}
Expression* destRef;
Expression* destIndex;
Expression* srcRef;
Expression* srcIndex;
Expression* length;
void finalize();
};
class ArrayFill : public SpecificExpression<Expression::ArrayFillId> {
public:
ArrayFill() = default;
ArrayFill(MixedArena& allocator) {}
Expression* ref;
Expression* index;
Expression* value;
Expression* size;
void finalize();
};
class ArrayInitData : public SpecificExpression<Expression::ArrayInitDataId> {
public:
ArrayInitData() = default;
ArrayInitData(MixedArena& allocator) {}
Name segment;
Expression* ref;
Expression* index;
Expression* offset;
Expression* size;
void finalize();
};
class ArrayInitElem : public SpecificExpression<Expression::ArrayInitElemId> {
public:
ArrayInitElem() = default;
ArrayInitElem(MixedArena& allocator) {}
Name segment;
Expression* ref;
Expression* index;
Expression* offset;
Expression* size;
void finalize();
};
class RefAs : public SpecificExpression<Expression::RefAsId> {
public:
RefAs() = default;
RefAs(MixedArena& allocator) {}
RefAsOp op;
Expression* value;
void finalize();
};
class StringNew : public SpecificExpression<Expression::StringNewId> {
public:
StringNew() = default;
StringNew(MixedArena& allocator) {}
StringNewOp op;
Expression* ptr;
Expression* length = nullptr;
Expression* start = nullptr;
Expression* end = nullptr;
bool try_ = false;
void finalize();
};
class StringConst : public SpecificExpression<Expression::StringConstId> {
public:
StringConst() = default;
StringConst(MixedArena& allocator) {}
Name string;
void finalize();
};
class StringMeasure : public SpecificExpression<Expression::StringMeasureId> {
public:
StringMeasure() = default;
StringMeasure(MixedArena& allocator) {}
StringMeasureOp op;
Expression* ref;
void finalize();
};
class StringEncode : public SpecificExpression<Expression::StringEncodeId> {
public:
StringEncode() = default;
StringEncode(MixedArena& allocator) {}
StringEncodeOp op;
Expression* ref;
Expression* ptr;
Expression* start = nullptr;
void finalize();
};
class StringConcat : public SpecificExpression<Expression::StringConcatId> {
public:
StringConcat() = default;
StringConcat(MixedArena& allocator) {}
Expression* left;
Expression* right;
void finalize();
};
class StringEq : public SpecificExpression<Expression::StringEqId> {
public:
StringEq() = default;
StringEq(MixedArena& allocator) {}
StringEqOp op;
Expression* left;
Expression* right;
void finalize();
};
class StringAs : public SpecificExpression<Expression::StringAsId> {
public:
StringAs() = default;
StringAs(MixedArena& allocator) {}
StringAsOp op;
Expression* ref;
void finalize();
};
class StringWTF8Advance
: public SpecificExpression<Expression::StringWTF8AdvanceId> {
public:
StringWTF8Advance() = default;
StringWTF8Advance(MixedArena& allocator) {}
Expression* ref;
Expression* pos;
Expression* bytes;
void finalize();
};
class StringWTF16Get : public SpecificExpression<Expression::StringWTF16GetId> {
public:
StringWTF16Get() = default;
StringWTF16Get(MixedArena& allocator) {}
Expression* ref;
Expression* pos;
void finalize();
};
class StringIterNext : public SpecificExpression<Expression::StringIterNextId> {
public:
StringIterNext() = default;
StringIterNext(MixedArena& allocator) {}
Expression* ref;
void finalize();
};
class StringIterMove : public SpecificExpression<Expression::StringIterMoveId> {
public:
StringIterMove() = default;
StringIterMove(MixedArena& allocator) {}
StringIterMoveOp op;
Expression* ref;
Expression* num;
void finalize();
};
class StringSliceWTF : public SpecificExpression<Expression::StringSliceWTFId> {
public:
StringSliceWTF() = default;
StringSliceWTF(MixedArena& allocator) {}
StringSliceWTFOp op;
Expression* ref;
Expression* start;
Expression* end;
void finalize();
};
class StringSliceIter
: public SpecificExpression<Expression::StringSliceIterId> {
public:
StringSliceIter() = default;
StringSliceIter(MixedArena& allocator) {}
Expression* ref;
Expression* num;
void finalize();
};
class ContBind : public SpecificExpression<Expression::ContBindId> {
public:
ContBind(MixedArena& allocator) : operands(allocator) {}
HeapType contTypeBefore;
HeapType contTypeAfter;
ExpressionList operands;
Expression* cont;
void finalize();
};
class ContNew : public SpecificExpression<Expression::ContNewId> {
public:
ContNew() = default;
ContNew(MixedArena& allocator) {}
HeapType contType;
Expression* func;
void finalize();
};
class Resume : public SpecificExpression<Expression::ResumeId> {
public:
Resume(MixedArena& allocator)
: handlerTags(allocator), handlerBlocks(allocator), operands(allocator),
sentTypes(allocator) {}
HeapType contType;
ArenaVector<Name> handlerTags;
ArenaVector<Name> handlerBlocks;
ExpressionList operands;
Expression* cont;
void finalize(Module* wasm = nullptr);
ArenaVector<Type> sentTypes;
};
struct Named {
Name name;
bool hasExplicitName = false;
void setName(Name name_, bool hasExplicitName_) {
name = name_;
hasExplicitName = hasExplicitName_;
}
void setExplicitName(Name name_) { setName(name_, true); }
};
struct Importable : Named {
Name module, base;
bool imported() const { return module.is(); }
};
class Function;
using BinaryLocation = uint32_t;
struct BinaryLocations {
struct Span {
BinaryLocation start = 0, end = 0;
};
std::unordered_map<Expression*, Span> expressions;
using DelimiterLocations = ZeroInitSmallVector<BinaryLocation, 1>;
enum DelimiterId : size_t { Else = 0, Invalid = size_t(-1) };
std::unordered_map<Expression*, DelimiterLocations> delimiters;
struct FunctionLocations {
BinaryLocation start = 0;
BinaryLocation declarations = 0;
BinaryLocation end = 0;
};
std::unordered_map<Function*, FunctionLocations> functions;
};
class StackInst;
using StackIR = std::vector<StackInst*>;
class Function : public Importable {
public:
HeapType type = HeapType(Signature()); IRProfile profile = IRProfile::Normal;
std::vector<Type> vars;
Expression* body = nullptr;
std::unique_ptr<StackIR> stackIR;
std::unordered_map<Index, Name> localNames;
std::unordered_map<Name, Index> localIndices;
struct DebugLocation {
BinaryLocation fileIndex, lineNumber, columnNumber;
bool operator==(const DebugLocation& other) const {
return fileIndex == other.fileIndex && lineNumber == other.lineNumber &&
columnNumber == other.columnNumber;
}
bool operator!=(const DebugLocation& other) const {
return !(*this == other);
}
bool operator<(const DebugLocation& other) const {
return fileIndex != other.fileIndex
? fileIndex < other.fileIndex
: lineNumber != other.lineNumber
? lineNumber < other.lineNumber
: columnNumber < other.columnNumber;
}
};
std::unordered_map<Expression*, DebugLocation> debugLocations;
std::set<DebugLocation> prologLocation;
std::set<DebugLocation> epilogLocation;
std::unordered_map<Expression*, BinaryLocations::Span> expressionLocations;
std::unordered_map<Expression*, BinaryLocations::DelimiterLocations>
delimiterLocations;
BinaryLocations::FunctionLocations funcLocation;
bool noFullInline = false;
bool noPartialInline = false;
Signature getSig() { return type.getSignature(); }
Type getParams() { return getSig().params; }
Type getResults() { return getSig().results; }
void setParams(Type params) { type = Signature(params, getResults()); }
void setResults(Type results) { type = Signature(getParams(), results); }
size_t getNumParams();
size_t getNumVars();
size_t getNumLocals();
bool isParam(Index index);
bool isVar(Index index);
Name getLocalName(Index index);
Index getLocalIndex(Name name);
bool hasLocalIndex(Name name) const;
Index getVarIndexBase();
Type getLocalType(Index index);
Name getLocalNameOrDefault(Index index);
Name getLocalNameOrGeneric(Index index);
bool hasLocalName(Index index) const;
void setLocalName(Index index, Name name);
void clearNames();
void clearDebugInfo();
};
enum class ExternalKind {
Function = 0,
Table = 1,
Memory = 2,
Global = 3,
Tag = 4,
Invalid = -1
};
enum class ModuleItemKind {
Function = 0,
Table = 1,
Memory = 2,
Global = 3,
Tag = 4,
DataSegment = 5,
ElementSegment = 6,
Invalid = -1
};
class Export {
public:
Name name;
Name value; ExternalKind kind;
};
class ElementSegment : public Named {
public:
Name table;
Expression* offset = nullptr;
Type type = Type(HeapType::func, Nullable);
std::vector<Expression*> data;
ElementSegment() = default;
ElementSegment(Name table,
Expression* offset,
Type type = Type(HeapType::func, Nullable))
: table(table), offset(offset), type(type) {}
ElementSegment(Name table,
Expression* offset,
Type type,
std::vector<Expression*>& init)
: table(table), offset(offset), type(type) {
data.swap(init);
}
};
class Table : public Importable {
public:
static const Address::address32_t kPageSize = 1;
static const Index kUnlimitedSize = Index(-1);
static const Index kMaxSize = Index(-1);
Address initial = 0;
Address max = kMaxSize;
Type type = Type(HeapType::func, Nullable);
bool hasMax() { return max != kUnlimitedSize; }
void clear() {
name = "";
initial = 0;
max = kMaxSize;
}
};
class DataSegment : public Named {
public:
Name memory;
bool isPassive = false;
Expression* offset = nullptr;
std::vector<char> data; };
class Memory : public Importable {
public:
static const Address::address32_t kPageSize = 64 * 1024;
static const Address::address64_t kUnlimitedSize = Address::address64_t(-1);
static const Address::address32_t kMaxSize32 =
(uint64_t(4) * 1024 * 1024 * 1024) / kPageSize;
static const Address::address64_t kMaxSize64 = 1ull << (64 - 16);
Address initial = 0; Address max = kMaxSize32;
bool shared = false;
Type indexType = Type::i32;
bool hasMax() { return max != kUnlimitedSize; }
bool is64() { return indexType == Type::i64; }
void clear() {
name = "";
initial = 0;
max = kMaxSize32;
shared = false;
indexType = Type::i32;
}
};
class Global : public Importable {
public:
Type type;
Expression* init = nullptr;
bool mutable_ = false;
};
class Tag : public Importable {
public:
Signature sig;
};
class CustomSection {
public:
std::string name;
std::vector<char> data;
};
class DylinkSection {
public:
bool isLegacy = false;
Index memorySize, memoryAlignment, tableSize, tableAlignment;
std::vector<Name> neededDynlibs;
std::vector<char> tail;
};
class Module {
public:
std::vector<std::unique_ptr<Export>> exports;
std::vector<std::unique_ptr<Function>> functions;
std::vector<std::unique_ptr<Global>> globals;
std::vector<std::unique_ptr<Tag>> tags;
std::vector<std::unique_ptr<ElementSegment>> elementSegments;
std::vector<std::unique_ptr<Memory>> memories;
std::vector<std::unique_ptr<DataSegment>> dataSegments;
std::vector<std::unique_ptr<Table>> tables;
Name start;
std::vector<CustomSection> customSections;
std::unique_ptr<DylinkSection> dylinkSection;
std::vector<std::string> debugInfoFileNames;
FeatureSet features = FeatureSet::MVP;
bool hasFeaturesSection = false;
Name name;
std::unordered_map<HeapType, TypeNames> typeNames;
MixedArena allocator;
private:
std::unordered_map<Name, Export*> exportsMap;
std::unordered_map<Name, Function*> functionsMap;
std::unordered_map<Name, Table*> tablesMap;
std::unordered_map<Name, Memory*> memoriesMap;
std::unordered_map<Name, ElementSegment*> elementSegmentsMap;
std::unordered_map<Name, DataSegment*> dataSegmentsMap;
std::unordered_map<Name, Global*> globalsMap;
std::unordered_map<Name, Tag*> tagsMap;
public:
Module() = default;
Export* getExport(Name name);
Function* getFunction(Name name);
Table* getTable(Name name);
ElementSegment* getElementSegment(Name name);
Memory* getMemory(Name name);
DataSegment* getDataSegment(Name name);
Global* getGlobal(Name name);
Tag* getTag(Name name);
Export* getExportOrNull(Name name);
Table* getTableOrNull(Name name);
Memory* getMemoryOrNull(Name name);
ElementSegment* getElementSegmentOrNull(Name name);
DataSegment* getDataSegmentOrNull(Name name);
Function* getFunctionOrNull(Name name);
Global* getGlobalOrNull(Name name);
Tag* getTagOrNull(Name name);
Importable* getImport(ModuleItemKind kind, Name name);
Importable* getImportOrNull(ModuleItemKind kind, Name name);
Export* addExport(Export* curr);
Function* addFunction(Function* curr);
Global* addGlobal(Global* curr);
Tag* addTag(Tag* curr);
Export* addExport(std::unique_ptr<Export>&& curr);
Function* addFunction(std::unique_ptr<Function>&& curr);
Table* addTable(std::unique_ptr<Table>&& curr);
ElementSegment* addElementSegment(std::unique_ptr<ElementSegment>&& curr);
Memory* addMemory(std::unique_ptr<Memory>&& curr);
DataSegment* addDataSegment(std::unique_ptr<DataSegment>&& curr);
Global* addGlobal(std::unique_ptr<Global>&& curr);
Tag* addTag(std::unique_ptr<Tag>&& curr);
void addStart(const Name& s);
void removeExport(Name name);
void removeFunction(Name name);
void removeTable(Name name);
void removeElementSegment(Name name);
void removeMemory(Name name);
void removeDataSegment(Name name);
void removeGlobal(Name name);
void removeTag(Name name);
void removeExports(std::function<bool(Export*)> pred);
void removeFunctions(std::function<bool(Function*)> pred);
void removeTables(std::function<bool(Table*)> pred);
void removeElementSegments(std::function<bool(ElementSegment*)> pred);
void removeMemories(std::function<bool(Memory*)> pred);
void removeDataSegments(std::function<bool(DataSegment*)> pred);
void removeGlobals(std::function<bool(Global*)> pred);
void removeTags(std::function<bool(Tag*)> pred);
void updateFunctionsMap();
void updateDataSegmentsMap();
void updateMaps();
void clearDebugInfo();
};
using ModuleExpression = std::pair<Module&, Expression*>;
struct ShallowExpression {
Expression* expr;
Module* module = nullptr;
};
}
namespace std {
template<> struct hash<wasm::Address> {
size_t operator()(const wasm::Address a) const {
return std::hash<wasm::Address::address64_t>()(a.addr);
}
};
std::ostream& operator<<(std::ostream& o, wasm::Module& module);
std::ostream& operator<<(std::ostream& o, wasm::Function& func);
std::ostream& operator<<(std::ostream& o, wasm::Expression& expression);
std::ostream& operator<<(std::ostream& o, wasm::ModuleExpression pair);
std::ostream& operator<<(std::ostream& o, wasm::ShallowExpression expression);
std::ostream& operator<<(std::ostream& o, wasm::StackInst& inst);
std::ostream& operator<<(std::ostream& o, wasm::StackIR& ir);
}
#endif