Source code

Revision control

Copy as Markdown

Other Tools

/*
* Copyright 2017 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_OPCODE_H_
#define WABT_OPCODE_H_
#include <vector>
#include "wabt/common.h"
#include "wabt/leb128.h"
#include "wabt/opcode-code-table.h"
namespace wabt {
class Features;
struct Opcode {
// Opcode enumerations.
//
// NOTE: this enum does not match the binary encoding.
//
enum Enum : uint32_t {
#define WABT_OPCODE(rtype, type1, type2, type3, mem_size, prefix, code, Name, \
text, decomp) \
Name,
#include "wabt/opcode.def"
#undef WABT_OPCODE
Invalid,
};
// Static opcode objects.
#define WABT_OPCODE(rtype, type1, type2, type3, mem_size, prefix, code, Name, \
text, decomp) \
static Opcode Name##_Opcode;
#include "wabt/opcode.def"
#undef WABT_OPCODE
Opcode() = default; // Provided so Opcode can be member of a union.
Opcode(Enum e) : enum_(e) {}
operator Enum() const { return enum_; }
static Opcode FromCode(uint32_t);
static Opcode FromCode(uint8_t prefix, uint32_t code);
bool HasPrefix() const { return GetInfo().prefix != 0; }
uint8_t GetPrefix() const { return GetInfo().prefix; }
uint32_t GetCode() const { return GetInfo().code; }
size_t GetLength() const { return GetBytes().size(); }
const char* GetName() const { return GetInfo().name; }
const char* GetDecomp() const {
return *GetInfo().decomp ? GetInfo().decomp : GetInfo().name;
}
Type GetResultType() const { return GetInfo().result_type; }
Type GetParamType1() const { return GetInfo().param_types[0]; }
Type GetParamType2() const { return GetInfo().param_types[1]; }
Type GetParamType3() const { return GetInfo().param_types[2]; }
Type GetParamType(int n) const { return GetInfo().param_types[n - 1]; }
Address GetMemorySize() const { return GetInfo().memory_size; }
// Get the byte sequence for this opcode, including prefix.
std::vector<uint8_t> GetBytes() const;
// Get the lane count of an extract/replace simd op.
uint32_t GetSimdLaneCount() const;
// Return 1 if |alignment| matches the alignment of |opcode|, or if
// |alignment| is WABT_USE_NATURAL_ALIGNMENT.
bool IsNaturallyAligned(Address alignment) const;
// If |alignment| is WABT_USE_NATURAL_ALIGNMENT, return the alignment of
// |opcode|, else return |alignment|.
Address GetAlignment(Address alignment) const;
static bool IsPrefixByte(uint8_t byte) {
return byte == kMathPrefix || byte == kThreadsPrefix || byte == kSimdPrefix;
}
bool IsEnabled(const Features& features) const;
bool IsInvalid() const { return enum_ >= Invalid; }
private:
static constexpr uint32_t kMathPrefix = 0xfc;
static constexpr uint32_t kThreadsPrefix = 0xfe;
static constexpr uint32_t kSimdPrefix = 0xfd;
struct Info {
const char* name;
const char* decomp;
Type result_type;
Type param_types[3];
Address memory_size;
uint8_t prefix;
uint32_t code;
uint32_t prefix_code; // See PrefixCode below. Used for fast lookup.
};
static uint32_t PrefixCode(uint8_t prefix, uint32_t code) {
if (code >= (1 << MAX_OPCODE_BITS)) {
// Clamp to (2^bits - 1), since we know that it is an invalid code.
code = (1 << MAX_OPCODE_BITS) - 1;
}
return (prefix << MAX_OPCODE_BITS) | code;
}
// The Opcode struct only stores an enumeration (Opcode::Enum) of all valid
// opcodes, densely packed. We want to be able to store invalid opcodes as
// well, for display to the user. To encode these, we use PrefixCode() to
// generate a uint32_t of the prefix/code pair, then negate the value so it
// doesn't overlap with the valid enum values. The negation is done using
// `~code + 1` since prefix_code is unsigned, and MSVC warns if you use - on
// an unsigned value.
//
// | 0 | Opcode::Invalid | INT32_MAX+1 UINT32_MAX |
// |---------------|-------------------------|---------------------------|
// | valid opcodes | unused space | invalid opcodes |
//
static Enum EncodeInvalidOpcode(uint32_t prefix_code) {
Enum result = static_cast<Enum>(~prefix_code + 1);
assert(result >= Invalid);
return result;
}
static void DecodeInvalidOpcode(Enum e,
uint8_t* out_prefix,
uint32_t* out_code) {
uint32_t prefix_code = ~static_cast<uint32_t>(e) + 1;
*out_prefix = prefix_code >> MAX_OPCODE_BITS;
*out_code = prefix_code & 0xff;
}
Info GetInfo() const;
static Info infos_[];
Enum enum_;
};
// static
inline Opcode Opcode::FromCode(uint32_t code) {
return FromCode(0, code);
}
// static
inline Opcode Opcode::FromCode(uint8_t prefix, uint32_t code) {
uint32_t prefix_code = PrefixCode(prefix, code);
if (WABT_LIKELY(prefix_code < WABT_ARRAY_SIZE(WabtOpcodeCodeTable))) {
uint32_t value = WabtOpcodeCodeTable[prefix_code];
// The default value in the table is 0. That's a valid value, but only if
// the code is 0 (for nop).
if (WABT_LIKELY(value != 0 || code == 0)) {
return Opcode(static_cast<Enum>(value));
}
}
return Opcode(EncodeInvalidOpcode(prefix_code));
}
} // namespace wabt
#endif // WABT_OPCODE_H_