Bug 1607440 - Introduce the Opcode abstraction. r=bbouvier

The `Opcode` wraps an `Op`, and if the `Op` is a prefix it also
carries the secondary opcode bits.  Implicit constructors from `Op`,
`MiscOp`, etc to `Opcode`, ensures that this will be pretty painless
to use.

Differential Revision: https://phabricator.services.mozilla.com/D58940

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Lars T Hansen 2020-01-09 17:54:16 +00:00
Родитель 15cf5c2afd
Коммит 6fa8ac7e16
3 изменённых файлов: 88 добавлений и 27 удалений

Просмотреть файл

@ -169,9 +169,7 @@ class WasmToken {
int64_t sint_;
FloatLiteralKind floatLiteralKind_;
ValType valueType_;
Op op_;
MiscOp miscOp_;
ThreadOp threadOp_;
Opcode opcode_;
U() : index_(0) {}
} u;
@ -211,30 +209,26 @@ class WasmToken {
MOZ_ASSERT(kind_ == ValueType || kind_ == Const);
u.valueType_ = valueType;
}
explicit WasmToken(Kind kind, Op op, const char16_t* begin,
explicit WasmToken(Kind kind, Opcode op, const char16_t* begin,
const char16_t* end)
: kind_(kind), begin_(begin), end_(end) {
MOZ_ASSERT(begin != end);
MOZ_ASSERT(kind_ == UnaryOpcode || kind_ == BinaryOpcode ||
kind_ == ComparisonOpcode || kind_ == ConversionOpcode ||
kind_ == Load || kind_ == Store);
u.op_ = op;
}
explicit WasmToken(Kind kind, MiscOp op, const char16_t* begin,
const char16_t* end)
: kind_(kind), begin_(begin), end_(end) {
MOZ_ASSERT(begin != end);
MOZ_ASSERT(kind_ == ExtraConversionOpcode);
u.miscOp_ = op;
}
explicit WasmToken(Kind kind, ThreadOp op, const char16_t* begin,
const char16_t* end)
: kind_(kind), begin_(begin), end_(end) {
MOZ_ASSERT(begin != end);
MOZ_ASSERT(kind_ == AtomicCmpXchg || kind_ == AtomicLoad ||
kind_ == AtomicRMW || kind_ == AtomicStore || kind_ == Wait ||
kind_ == Wake || kind_ == Fence);
u.threadOp_ = op;
#ifdef DEBUG
if (op.isOp()) {
MOZ_ASSERT(kind_ == UnaryOpcode || kind_ == BinaryOpcode ||
kind_ == ComparisonOpcode || kind_ == ConversionOpcode ||
kind_ == Load || kind_ == Store);
} else if (op.isMisc()) {
MOZ_ASSERT(kind_ == ExtraConversionOpcode);
} else if (op.isThread()) {
MOZ_ASSERT(kind_ == AtomicCmpXchg || kind_ == AtomicLoad ||
kind_ == AtomicRMW || kind_ == AtomicStore || kind_ == Wait ||
kind_ == Wake || kind_ == Fence);
} else {
MOZ_CRASH();
}
#endif
u.opcode_ = op;
}
explicit WasmToken(const char16_t* begin)
: kind_(Error), begin_(begin), end_(begin), u{} {}
@ -276,17 +270,17 @@ class WasmToken {
MOZ_ASSERT(kind_ == UnaryOpcode || kind_ == BinaryOpcode ||
kind_ == ComparisonOpcode || kind_ == ConversionOpcode ||
kind_ == Load || kind_ == Store);
return u.op_;
return u.opcode_.asOp();
}
MiscOp miscOp() const {
MOZ_ASSERT(kind_ == ExtraConversionOpcode);
return u.miscOp_;
return u.opcode_.asMisc();
}
ThreadOp threadOp() const {
MOZ_ASSERT(kind_ == AtomicCmpXchg || kind_ == AtomicLoad ||
kind_ == AtomicRMW || kind_ == AtomicStore || kind_ == Wait ||
kind_ == Wake);
return u.threadOp_;
return u.opcode_.asThread();
}
bool isOpcode() const {
switch (kind_) {

Просмотреть файл

@ -202,6 +202,61 @@ struct ShareableBytes : ShareableBase<ShareableBytes> {
typedef RefPtr<ShareableBytes> MutableBytes;
typedef RefPtr<const ShareableBytes> SharedBytes;
// The Opcode compactly and safely represents the primary opcode plus any
// extension, with convenient predicates and accessors.
class Opcode {
uint32_t bits_;
public:
MOZ_IMPLICIT Opcode(Op op) : bits_(uint32_t(op)) {
static_assert(size_t(Op::Limit) == 256, "fits");
MOZ_ASSERT(size_t(op) < size_t(Op::Limit));
}
MOZ_IMPLICIT Opcode(MiscOp op)
: bits_((uint32_t(op) << 8) | uint32_t(Op::MiscPrefix)) {
static_assert(size_t(MiscOp::Limit) <= 0xFFFFFF, "fits");
MOZ_ASSERT(size_t(op) < size_t(MiscOp::Limit));
}
MOZ_IMPLICIT Opcode(ThreadOp op)
: bits_((uint32_t(op) << 8) | uint32_t(Op::ThreadPrefix)) {
static_assert(size_t(ThreadOp::Limit) <= 0xFFFFFF, "fits");
MOZ_ASSERT(size_t(op) < size_t(ThreadOp::Limit));
}
MOZ_IMPLICIT Opcode(MozOp op)
: bits_((uint32_t(op) << 8) | uint32_t(Op::MozPrefix)) {
static_assert(size_t(MozOp::Limit) <= 0xFFFFFF, "fits");
MOZ_ASSERT(size_t(op) < size_t(MozOp::Limit));
}
bool isOp() const { return bits_ < uint32_t(Op::FirstPrefix); }
bool isMisc() const { return (bits_ & 255) == uint32_t(Op::MiscPrefix); }
bool isThread() const { return (bits_ & 255) == uint32_t(Op::ThreadPrefix); }
bool isMoz() const { return (bits_ & 255) == uint32_t(Op::MozPrefix); }
Op asOp() const {
MOZ_ASSERT(isOp());
return Op(bits_);
}
MiscOp asMisc() const {
MOZ_ASSERT(isMisc());
return MiscOp(bits_ >> 8);
}
ThreadOp asThread() const {
MOZ_ASSERT(isThread());
return ThreadOp(bits_ >> 8);
}
MozOp asMoz() const {
MOZ_ASSERT(isMoz());
return MozOp(bits_ >> 8);
}
uint32_t bits() const { return bits_; }
bool operator==(const Opcode& that) const { return bits_ == that.bits_; }
bool operator!=(const Opcode& that) const { return bits_ != that.bits_; }
};
// A PackedTypeCode represents a TypeCode paired with a refTypeIndex (valid only
// for TypeCode::Ref). PackedTypeCode is guaranteed to be POD. The TypeCode
// spans the full range of type codes including the specialized AnyRef, FuncRef,

Просмотреть файл

@ -441,6 +441,18 @@ class Encoder {
MOZ_ASSERT(size_t(op) < size_t(MozOp::Limit));
return writeFixedU8(uint8_t(Op::MozPrefix)) && writeVarU32(uint32_t(op));
}
MOZ_MUST_USE bool writeOp(Opcode opcode) {
// The Opcode constructor has asserted that `opcode` is meaningful, so no
// further correctness checking is necessary here.
uint32_t bits = opcode.bits();
if (!writeFixedU8(bits & 255)) {
return false;
}
if (opcode.isOp()) {
return true;
}
return writeVarU32(bits >> 8);
}
// Fixed-length encodings that allow back-patching.