--- a/js/src/asmjs/WasmBinary.h
+++ b/js/src/asmjs/WasmBinary.h
@@ -440,20 +440,33 @@ class Decoder
uint8_t u8;
if (!read(&u8))
return false;
*out = T(u8);
return true;
}
template <class T>
- T uncheckedRead() {
+ T uncheckedPeek() const {
MOZ_ASSERT(uintptr_t(end_ - cur_) >= sizeof(T));
T ret;
memcpy(&ret, cur_, sizeof(T));
+ return ret;
+ }
+
+ template <class T>
+ T uncheckedPeekEnum() const {
+ // See Encoder::writeEnum.
+ static_assert(mozilla::IsEnum<T>::value, "is an enum");
+ return (T)uncheckedPeek<uint8_t>();
+ }
+
+ template <class T>
+ T uncheckedRead() {
+ T ret = uncheckedPeek<T>();
cur_ += sizeof(T);
return ret;
}
template <class T>
T uncheckedReadEnum() {
// See Encoder::writeEnum.
static_assert(mozilla::IsEnum<T>::value, "is an enum");
@@ -563,16 +576,19 @@ class Decoder
byte = uncheckedReadU8();
MOZ_ASSERT(!(byte & 0xF0));
decoded |= uint32_t(byte) << 28;
return decoded;
}
Expr uncheckedReadExpr() {
return uncheckedReadEnum<Expr>();
}
+ Expr uncheckedPeekExpr() const {
+ return uncheckedPeekEnum<Expr>();
+ }
};
// Source coordinates for a call site. As they're read sequentially, we
// don't need to store the call's bytecode offset, unless we want to
// check its correctness in debug mode.
struct SourceCoords {
DebugOnly<size_t> offset; // after call opcode
uint32_t line;
--- a/js/src/asmjs/WasmIonCompile.cpp
+++ b/js/src/asmjs/WasmIonCompile.cpp
@@ -1178,16 +1178,17 @@ class FunctionCompiler
uint32_t readU32() { return decoder_.uncheckedReadU32(); }
uint32_t readVarU32() { return decoder_.uncheckedReadVarU32(); }
int32_t readI32() { return decoder_.uncheckedReadI32(); }
float readF32() { return decoder_.uncheckedReadF32(); }
double readF64() { return decoder_.uncheckedReadF64(); }
SimdConstant readI32X4() { return decoder_.uncheckedReadI32X4(); }
SimdConstant readF32X4() { return decoder_.uncheckedReadF32X4(); }
Expr readOpcode() { return decoder_.uncheckedReadExpr(); }
+ Expr peekOpcode() { return decoder_.uncheckedPeekExpr(); }
void readCallLineCol(uint32_t* line, uint32_t* column) {
const SourceCoords& sc = func_.sourceCoords(lastReadCallSite_++);
decoder_.assertCurrentIs(sc.offset);
*line = sc.line;
*column = sc.column;
}
@@ -1286,26 +1287,30 @@ class FunctionCompiler
return false;
unlabeledBreaks_.remove(p);
}
return true;
}
};
// A Type or Undefined, implicitly constructed from an ExprType and usabled as
-// an ExprType. Will assert if we're trying to access the type although we
+// an ExprType. Has two functions:
+// - in debug, will ensure that the expected type and the actual type of some
+// expressions match.
+// - provides a way to mean "no type" in the context of expression statements,
+// and will provoke assertions if we're trying to use an expected type when we
// don't have one.
class MaybeType
{
Maybe<ExprType> maybe_;
MaybeType() {}
public:
MOZ_IMPLICIT MaybeType(ExprType t) : maybe_() { maybe_.emplace(t); }
static MaybeType Undefined() { return MaybeType(); }
- operator bool() { return maybe_.isSome(); }
+ explicit operator bool() { return maybe_.isSome(); }
MOZ_IMPLICIT operator ExprType() { return maybe_.value(); }
};
static bool
EmitLiteral(FunctionCompiler& f, ExprType type, MDefinition**def)
{
switch (type) {
case ExprType::I32: {
@@ -1363,20 +1368,18 @@ EmitLoadGlobal(FunctionCompiler& f, Mayb
{
uint32_t index = f.readVarU32();
const AsmJSGlobalVariable& global = f.mg().globalVar(index);
*def = f.loadGlobalVar(global.globalDataOffset, global.isConst, ToMIRType(global.type));
MOZ_ASSERT_IF(type, global.type == type);
return true;
}
-static bool EmitExpr(FunctionCompiler&, MaybeType, Expr, MDefinition**, LabelVector* = nullptr);
static bool EmitExpr(FunctionCompiler&, MaybeType, MDefinition**, LabelVector* = nullptr);
static bool EmitExprStmt(FunctionCompiler&, MDefinition**, LabelVector* = nullptr);
-static bool EmitExprStmt(FunctionCompiler&, Expr, MDefinition**, LabelVector* = nullptr);
static bool EmitSimdBooleanLaneExpr(FunctionCompiler& f, MDefinition** def);
static bool
EmitLoadArray(FunctionCompiler& f, Scalar::Type scalarType, MDefinition** def)
{
NeedsBoundsCheck needsBoundsCheck = NeedsBoundsCheck(f.readU8());
MDefinition* ptr;
if (!EmitExpr(f, ExprType::I32, &ptr))
@@ -2442,28 +2445,25 @@ EmitIfElse(FunctionCompiler& f, bool has
return false;
if (!f.appendThenBlock(&thenBlocks))
return false;
if (hasElse) {
f.switchToElse(elseOrJoinBlock);
- Expr nextStmt(f.readOpcode());
- if (nextStmt == Expr::If) {
- hasElse = false;
- goto recurse;
- }
- if (nextStmt == Expr::IfElse) {
- hasElse = true;
+ Expr nextStmt = f.peekOpcode();
+ if (nextStmt == Expr::If || nextStmt == Expr::IfElse) {
+ hasElse = nextStmt == Expr::IfElse;
+ JS_ALWAYS_TRUE(f.readOpcode() == nextStmt);
goto recurse;
}
MDefinition* _;
- if (!EmitExprStmt(f, nextStmt, &_))
+ if (!EmitExprStmt(f, &_))
return false;
return f.joinIfElse(thenBlocks);
} else {
return f.joinIf(thenBlocks, elseOrJoinBlock);
}
}
@@ -2561,22 +2561,22 @@ EmitBreak(FunctionCompiler& f, bool hasL
{
if (!hasLabel)
return f.addBreak(nullptr);
uint32_t labelId = f.readU32();
return f.addBreak(&labelId);
}
static bool
-EmitExpr(FunctionCompiler& f, MaybeType type, Expr op, MDefinition** def, LabelVector* maybeLabels)
+EmitExpr(FunctionCompiler& f, MaybeType type, MDefinition** def, LabelVector* maybeLabels)
{
if (!f.mirGen().ensureBallast())
return false;
- switch (op) {
+ switch (Expr op = f.readOpcode()) {
case Expr::Nop:
return true;
case Expr::Block:
return EmitBlock(f, type, def);
case Expr::If:
case Expr::IfElse:
return EmitIfElse(f, HasElseBlock(op == Expr::IfElse));
case Expr::TableSwitch:
@@ -2932,31 +2932,19 @@ EmitExpr(FunctionCompiler& f, MaybeType
case Expr::Unreachable:
break;
}
MOZ_CRASH("unexpected wasm opcode");
}
static bool
-EmitExpr(FunctionCompiler& f, MaybeType type, MDefinition** def, LabelVector* maybeLabels)
-{
- return EmitExpr(f, type, f.readOpcode(), def, maybeLabels);
-}
-
-static bool
-EmitExprStmt(FunctionCompiler& f, Expr op, MDefinition** def, LabelVector* maybeLabels)
-{
- return EmitExpr(f, MaybeType::Undefined(), op, def, maybeLabels);
-}
-
-static bool
EmitExprStmt(FunctionCompiler& f, MDefinition** def, LabelVector* maybeLabels)
{
- return EmitExprStmt(f, f.readOpcode(), def, maybeLabels);
+ return EmitExpr(f, MaybeType::Undefined(), def, maybeLabels);
}
bool
wasm::IonCompileFunction(IonCompileTask* task)
{
int64_t before = PRMJ_Now();
const FuncBytecode& func = task->func();