diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/opcode.cc | 35 | ||||
-rw-r--r-- | src/opcode.h | 36 |
2 files changed, 53 insertions, 18 deletions
diff --git a/src/opcode.cc b/src/opcode.cc index d5b305bf..3afd61ba 100644 --- a/src/opcode.cc +++ b/src/opcode.cc @@ -37,11 +37,6 @@ Opcode::Info Opcode::infos_[] = { #undef WABT_OPCODE // static -Opcode::Info Opcode::invalid_info_ = { - "<invalid>", Type::Void, Type::Void, Type::Void, 0, 0, 0, 0, -}; - -// static Opcode Opcode::FromCode(uint32_t code) { return FromCode(0, code); } @@ -49,20 +44,32 @@ Opcode Opcode::FromCode(uint32_t code) { // static Opcode Opcode::FromCode(uint8_t prefix, uint32_t code) { uint32_t prefix_code = PrefixCode(prefix, code); - auto iter = - std::lower_bound(infos_, infos_ + WABT_ARRAY_SIZE(infos_), prefix_code, - [](const Info& info, uint32_t prefix_code) { - return info.prefix_code < prefix_code; - }); - - if (iter->prefix_code != prefix_code) - return Opcode(Invalid); + auto begin = infos_; + auto end = infos_ + WABT_ARRAY_SIZE(infos_); + auto iter = std::lower_bound(begin, end, prefix_code, + [](const Info& info, uint32_t prefix_code) { + return info.prefix_code < prefix_code; + }); + if (iter == end || iter->prefix_code != prefix_code) { + return Opcode(EncodeInvalidOpcode(prefix_code)); + } return Opcode(static_cast<Enum>(iter - infos_)); } Opcode::Info Opcode::GetInfo() const { - return enum_ < Invalid ? infos_[enum_] : invalid_info_; + if (enum_ < Invalid) { + return infos_[enum_]; + } + + uint8_t prefix; + uint32_t code; + DecodeInvalidOpcode(enum_, &prefix, &code); + const Info invalid_info = { + "<invalid>", Type::Void, Type::Void, Type::Void, + 0, prefix, code, PrefixCode(prefix, code), + }; + return invalid_info; } bool Opcode::IsNaturallyAligned(Address alignment) const { diff --git a/src/opcode.h b/src/opcode.h index 30417ec7..f91f3278 100644 --- a/src/opcode.h +++ b/src/opcode.h @@ -28,7 +28,7 @@ struct Opcode { // // NOTE: this enum does not match the binary encoding. // - enum Enum { + enum Enum : uint32_t { #define WABT_OPCODE(rtype, type1, type2, mem_size, prefix, code, Name, text) \ Name, #include "src/opcode.def" @@ -66,12 +66,15 @@ struct Opcode { // |opcode|, else return |alignment|. Address GetAlignment(Address alignment) const; - static bool IsPrefixByte(uint8_t byte) { return byte >= kFirstPrefix; } + static bool IsPrefixByte(uint8_t byte) { + return byte == kMathPrefix || byte == kThreadsPrefix; + } bool IsEnabled(const Features& features) const; private: - static const uint32_t kFirstPrefix = 0xfc; + static const uint32_t kMathPrefix = 0xfc; + static const uint32_t kThreadsPrefix = 0xfe; struct Info { const char* name; @@ -90,9 +93,34 @@ struct Opcode { return (prefix << 8) | 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 >> 8; + *out_code = prefix_code & 0xff; + } + Info GetInfo() const; static Info infos_[]; - static Info invalid_info_; Enum enum_; }; |