#pragma once #include #include #include "WAVM/IR/IR.h" #include "WAVM/IR/Operators.h" #include "WAVM/IR/Types.h" #include "WAVM/Inline/Assert.h" #include "WAVM/Inline/BasicTypes.h" #include "WAVM/Inline/Serialization.h" #include "WAVM/Platform/Defines.h" #include "OperatorTable.h" namespace WAVM { namespace IR { // Structures for operator immediates struct NoImm { }; struct MemoryImm { Uptr memoryIndex; }; struct MemoryCopyImm { Uptr destMemoryIndex; Uptr sourceMemoryIndex; }; struct TableImm { Uptr tableIndex; }; struct TableCopyImm { Uptr destTableIndex; Uptr sourceTableIndex; }; struct ControlStructureImm { IndexedBlockType type; }; struct SelectImm { // ValueType::any represents a legacy select with the type inferred from the first operand // following the condition. ValueType type; }; struct BranchImm { Uptr targetDepth; }; struct BranchTableImm { Uptr defaultTargetDepth; // An index into the FunctionDef's branchTables array. Uptr branchTableIndex; }; template struct LiteralImm { Value value; }; template struct GetOrSetVariableImm { Uptr variableIndex; }; struct FunctionImm { Uptr functionIndex; }; struct CallIndirectImm { IndexedFunctionType type; Uptr tableIndex; }; template struct LoadOrStoreImm { U8 alignmentLog2; U32 offset; Uptr memoryIndex; }; template struct LaneIndexImm { U8 laneIndex; }; template struct ShuffleImm { U8 laneIndices[numLanes]; }; template struct AtomicLoadOrStoreImm { U8 alignmentLog2; U32 offset; Uptr memoryIndex; }; enum class MemoryOrder { sequentiallyConsistent = 0 }; struct AtomicFenceImm { MemoryOrder order; }; struct ExceptionTypeImm { Uptr exceptionTypeIndex; }; struct RethrowImm { Uptr catchDepth; }; struct DataSegmentAndMemImm { Uptr dataSegmentIndex; Uptr memoryIndex; }; struct DataSegmentImm { Uptr dataSegmentIndex; }; struct ElemSegmentAndTableImm { Uptr elemSegmentIndex; Uptr tableIndex; }; struct ElemSegmentImm { Uptr elemSegmentIndex; }; enum class Opcode : U16 { #define VISIT_OPCODE(opcode, name, ...) name = opcode, WAVM_ENUM_OPERATORS(VISIT_OPCODE) #undef VISIT_OPCODE }; static constexpr U64 maxSingleByteOpcode = 0xdf; WAVM_PACKED_STRUCT(template struct OpcodeAndImm { Opcode opcode; Imm imm; }); // Specialize for the empty immediate struct so they don't take an extra byte of space. template<> struct OpcodeAndImm { union { Opcode opcode; NoImm imm; }; }; // Decodes an operator from an input stream and dispatches by opcode. struct OperatorDecoderStream { OperatorDecoderStream(const std::vector& codeBytes) : nextByte(codeBytes.data()), end(codeBytes.data() + codeBytes.size()) { } operator bool() const { return nextByte < end; } template typename Visitor::Result decodeOp(Visitor& visitor) { WAVM_ASSERT(nextByte + sizeof(Opcode) <= end); Opcode opcode; memcpy(&opcode, nextByte, sizeof(Opcode)); switch(opcode) { #define VISIT_OPCODE(opcode, name, nameString, Imm, ...) \ case Opcode::name: { \ WAVM_ASSERT(nextByte + sizeof(OpcodeAndImm) <= end); \ OpcodeAndImm encodedOperator; \ memcpy(&encodedOperator, nextByte, sizeof(OpcodeAndImm)); \ nextByte += sizeof(OpcodeAndImm); \ return visitor.name(encodedOperator.imm); \ } WAVM_ENUM_OPERATORS(VISIT_OPCODE) #undef VISIT_OPCODE default: WAVM_UNREACHABLE(); } } template typename Visitor::Result decodeOpWithoutConsume(Visitor& visitor) { const U8* savedNextByte = nextByte; typename Visitor::Result result = decodeOp(visitor); nextByte = savedNextByte; return result; } private: const U8* nextByte; const U8* end; }; // Encodes an operator to an output stream. struct OperatorEncoderStream { OperatorEncoderStream(Serialization::OutputStream& inByteStream) : byteStream(inByteStream) { } #define VISIT_OPCODE(_, name, nameString, Imm, ...) \ void name(Imm imm = {}) \ { \ OpcodeAndImm encodedOperator; \ encodedOperator.opcode = Opcode::name; \ encodedOperator.imm = imm; \ memcpy((OpcodeAndImm*)byteStream.advance(sizeof(OpcodeAndImm)), \ &encodedOperator, \ sizeof(OpcodeAndImm)); \ } WAVM_ENUM_OPERATORS(VISIT_OPCODE) #undef VISIT_OPCODE private: Serialization::OutputStream& byteStream; }; WAVM_API const char* getOpcodeName(Opcode opcode); struct NonParametricOpSignatures { #define VISIT_OP(_1, name, ...) FunctionType name; WAVM_ENUM_NONCONTROL_NONPARAMETRIC_OPERATORS(VISIT_OP) #undef VISIT_OP }; WAVM_API const NonParametricOpSignatures& getNonParametricOpSigs(); }}