summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/opcode.cc35
-rw-r--r--src/opcode.h36
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_;
};