Bug 1311994 - Baldr: add flags immediates to current_memory/grow_memory/call_indirect (r=sunfish)

MozReview-Commit-ID: 4qwtPliyesH

--HG--
extra : rebase_source : a853549266fb1c3c763b90680eb5637e1cc13cb5
This commit is contained in:
Luke Wagner 2016-10-24 13:20:53 -05:00
Родитель 440f0a594e
Коммит b615e9b281
12 изменённых файлов: 254 добавлений и 111 удалений

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

@ -195,10 +195,12 @@ enum class AstExprKind
ComparisonOperator,
Const,
ConversionOperator,
CurrentMemory,
Drop,
First,
GetGlobal,
GetLocal,
GrowMemory,
If,
Load,
Nop,
@ -210,7 +212,6 @@ enum class AstExprKind
Store,
TernaryOperator,
UnaryOperator,
NullaryOperator,
Unreachable
};
@ -545,6 +546,28 @@ class AstStore : public AstExpr
AstExpr& value() const { return *value_; }
};
class AstCurrentMemory final : public AstExpr
{
public:
static const AstExprKind Kind = AstExprKind::CurrentMemory;
explicit AstCurrentMemory()
: AstExpr(Kind, ExprType::I32)
{}
};
class AstGrowMemory final : public AstExpr
{
AstExpr* op_;
public:
static const AstExprKind Kind = AstExprKind::GrowMemory;
explicit AstGrowMemory(AstExpr* op)
: AstExpr(Kind, ExprType::I32), op_(op)
{}
AstExpr* op() const { return op_; }
};
class AstBranchTable : public AstExpr
{
AstExpr& index_;
@ -873,20 +896,6 @@ class AstModule : public AstNode
}
};
class AstNullaryOperator final : public AstExpr
{
Expr expr_;
public:
static const AstExprKind Kind = AstExprKind::NullaryOperator;
explicit AstNullaryOperator(Expr expr)
: AstExpr(Kind, ExprType::Limit),
expr_(expr)
{}
Expr expr() const { return expr_; }
};
class AstUnaryOperator final : public AstExpr
{
Expr expr_;

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

@ -2302,6 +2302,9 @@ class BaseCompiler
void builtinInstanceMethodCall(SymbolicAddress builtin, const ABIArg& instanceArg,
const FunctionCall& call)
{
// Builtin method calls assumed the TLS register has been set.
loadFromFramePtr(WasmTlsReg, frameOffsetFromSlot(tlsSlot_, MIRType::Pointer));
CallSiteDesc desc(call.lineOrBytecode_, CallSiteDesc::Symbolic);
masm.wasmCallBuiltinInstanceMethod(instanceArg, builtin);
}
@ -6229,23 +6232,23 @@ BaseCompiler::emitGrowMemory()
if (deadCode_)
return true;
uint32_t lineOrBytecode = readCallSiteLineOrBytecode();
Nothing arg;
if (!iter_.readGrowMemory(&arg))
return false;
sync();
uint32_t numArgs = 1;
size_t stackSpace = stackConsumed(numArgs);
FunctionCall baselineCall(lineOrBytecode);
FunctionCall baselineCall(readCallSiteLineOrBytecode());
beginCall(baselineCall, EscapesSandbox(true), IsBuiltinCall(true));
ABIArg instanceArg = reserveArgument(baselineCall);
if (!emitCallArgs(SigI_, baselineCall))
return false;
startCallArgs(baselineCall, stackArgAreaSize(SigI_));
if (!iter_.readCallReturn(ExprType::I32))
return false;
passArg(baselineCall, ValType::I32, peek(0));
builtinInstanceMethodCall(SymbolicAddress::GrowMemory, instanceArg, baselineCall);
@ -6265,20 +6268,17 @@ BaseCompiler::emitCurrentMemory()
if (deadCode_)
return true;
uint32_t lineOrBytecode = readCallSiteLineOrBytecode();
if (!iter_.readCurrentMemory())
return false;
sync();
FunctionCall baselineCall(lineOrBytecode);
FunctionCall baselineCall(readCallSiteLineOrBytecode());
beginCall(baselineCall, EscapesSandbox(true), IsBuiltinCall(true));
ABIArg instanceArg = reserveArgument(baselineCall);
if (!emitCallArgs(Sig_, baselineCall))
return false;
if (!iter_.readCallReturn(ExprType::I32))
return false;
startCallArgs(baselineCall, stackArgAreaSize(Sig_));
builtinInstanceMethodCall(SymbolicAddress::CurrentMemory, instanceArg, baselineCall);

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

@ -153,6 +153,11 @@ enum class GlobalFlags
AllowedMask = 0x1
};
enum class MemoryTableFlags
{
Default = 0x0
};
enum class Expr : uint32_t // fix type so we can cast from any u16 in decoder
{
// Control flow operators

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

@ -110,7 +110,6 @@ wasm::Classify(Expr expr)
case Expr::B8x16not:
case Expr::B16x8not:
case Expr::B32x4not:
case Expr::GrowMemory:
return ExprKind::Unary;
case Expr::I32Add:
case Expr::I32Sub:
@ -491,7 +490,9 @@ wasm::Classify(Expr expr)
case Expr::F32x4lessThanOrEqual:
return ExprKind::SimdComparison;
case Expr::CurrentMemory:
return ExprKind::Nullary;
return ExprKind::CurrentMemory;
case Expr::GrowMemory:
return ExprKind::GrowMemory;
}
MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("unimplemented opcode");
}

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

@ -68,6 +68,8 @@ enum class ExprKind {
Load,
Store,
TeeStore,
CurrentMemory,
GrowMemory,
Select,
GetLocal,
SetLocal,
@ -561,7 +563,8 @@ class MOZ_STACK_CLASS ExprIter : private Policy
MOZ_MUST_USE bool readTeeStore(ValType resultType, uint32_t byteSize,
LinearMemoryAddress<Value>* addr, Value* value);
MOZ_MUST_USE bool readNop();
MOZ_MUST_USE bool readNullary(ValType retType);
MOZ_MUST_USE bool readCurrentMemory();
MOZ_MUST_USE bool readGrowMemory(Value* input);
MOZ_MUST_USE bool readSelect(ValType* type,
Value* trueValue, Value* falseValue, Value* condition);
MOZ_MUST_USE bool readGetLocal(const ValTypeVector& locals, uint32_t* id);
@ -1348,13 +1351,41 @@ ExprIter<Policy>::readNop()
template <typename Policy>
inline bool
ExprIter<Policy>::readNullary(ValType retType)
ExprIter<Policy>::readCurrentMemory()
{
MOZ_ASSERT(Classify(expr_) == ExprKind::Nullary);
MOZ_ASSERT(Classify(expr_) == ExprKind::CurrentMemory);
if (!push(retType))
uint32_t flags;
if (!readVarU32(&flags))
return false;
if (Validate && flags != uint32_t(MemoryTableFlags::Default))
return fail("unexpected flags");
if (!push(ValType::I32))
return false;
return true;
}
template <typename Policy>
inline bool
ExprIter<Policy>::readGrowMemory(Value* input)
{
MOZ_ASSERT(Classify(expr_) == ExprKind::GrowMemory);
uint32_t flags;
if (!readVarU32(&flags))
return false;
if (Validate && flags != uint32_t(MemoryTableFlags::Default))
return fail("unexpected flags");
if (!popWithType(ValType::I32, input))
return false;
infalliblePush(ValType::I32);
return true;
}
@ -1725,6 +1756,13 @@ ExprIter<Policy>::readCallIndirect(uint32_t* sigIndex, Value* callee)
if (!readVarU32(sigIndex))
return fail("unable to read call_indirect signature index");
uint32_t flags;
if (!readVarU32(&flags))
return false;
if (Validate && flags != uint32_t(MemoryTableFlags::Default))
return fail("unexpected flags");
if (reachable_) {
if (!popWithType(ValType::I32, callee))
return false;

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

@ -672,22 +672,6 @@ AstDecodeUnary(AstDecodeContext& c, ValType type, Expr expr)
return true;
}
static bool
AstDecodeNullary(AstDecodeContext& c, ValType type, Expr expr)
{
if (!c.iter().readNullary(type))
return false;
AstNullaryOperator* nullary = new(c.lifo) AstNullaryOperator(expr);
if (!nullary)
return false;
if (!c.push(AstDecodeStackItem(nullary)))
return false;
return true;
}
static bool
AstDecodeBinary(AstDecodeContext& c, ValType type, Expr expr)
{
@ -815,6 +799,40 @@ AstDecodeStore(AstDecodeContext& c, ValType type, uint32_t byteSize, Expr expr)
return true;
}
static bool
AstDecodeCurrentMemory(AstDecodeContext& c)
{
if (!c.iter().readCurrentMemory())
return false;
AstCurrentMemory* gm = new(c.lifo) AstCurrentMemory();
if (!gm)
return false;
if (!c.push(AstDecodeStackItem(gm)))
return false;
return true;
}
static bool
AstDecodeGrowMemory(AstDecodeContext& c)
{
if (!c.iter().readGrowMemory(nullptr))
return false;
AstDecodeStackItem op = c.popCopy();
AstGrowMemory* gm = new(c.lifo) AstGrowMemory(op.expr);
if (!gm)
return false;
if (!c.push(AstDecodeStackItem(gm)))
return false;
return true;
}
static bool
AstDecodeBranch(AstDecodeContext& c, Expr expr)
{
@ -1088,7 +1106,6 @@ AstDecodeExpr(AstDecodeContext& c)
case Expr::I32Clz:
case Expr::I32Ctz:
case Expr::I32Popcnt:
case Expr::GrowMemory:
if (!AstDecodeUnary(c, ValType::I32, expr))
return false;
break;
@ -1361,6 +1378,14 @@ AstDecodeExpr(AstDecodeContext& c)
if (!AstDecodeStore(c, ValType::F64, 8, expr))
return false;
break;
case Expr::CurrentMemory:
if (!AstDecodeCurrentMemory(c))
return false;
break;
case Expr::GrowMemory:
if (!AstDecodeGrowMemory(c))
return false;
break;
case Expr::SetGlobal:
if (!AstDecodeSetGlobal(c))
return false;
@ -1382,10 +1407,6 @@ AstDecodeExpr(AstDecodeContext& c)
if (!AstDecodeReturn(c))
return false;
break;
case Expr::CurrentMemory:
if (!AstDecodeNullary(c, ValType::I32, expr))
return false;
break;
case Expr::Unreachable:
if (!c.iter().readUnreachable())
return false;

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

@ -316,19 +316,6 @@ PrintBlockLevelExpr(WasmPrintContext& c, AstExpr& expr, bool isLast)
/*****************************************************************************/
// binary format parsing and rendering
static bool
PrintNullaryOperator(WasmPrintContext& c, AstNullaryOperator& op)
{
const char* opStr;
switch (op.expr()) {
case Expr::CurrentMemory: opStr = "curent_memory"; break;
default: return false;
}
return c.buffer.append(opStr, strlen(opStr));
}
static bool
PrintNop(WasmPrintContext& c)
{
@ -654,7 +641,6 @@ PrintUnaryOperator(WasmPrintContext& c, AstUnaryOperator& op)
case Expr::F64Ceil: opStr = "f64.ceil"; break;
case Expr::F64Floor: opStr = "f64.floor"; break;
case Expr::F64Sqrt: opStr = "f64.sqrt"; break;
case Expr::GrowMemory: opStr = "grow_memory"; break;
default: return false;
}
@ -1361,6 +1347,31 @@ PrintFirst(WasmPrintContext& c, AstFirst& first)
return true;
}
static bool
PrintCurrentMemory(WasmPrintContext& c, AstCurrentMemory& cm)
{
return c.buffer.append("current_memory");
}
static bool
PrintGrowMemory(WasmPrintContext& c, AstGrowMemory& gm)
{
if (!c.buffer.append("grow_memory("))
return false;
PrintOperatorPrecedence lastPrecedence = c.currentPrecedence;
c.currentPrecedence = ExpressionPrecedence;
if (!PrintExpr(c, *gm.op()))
return false;
if (!c.buffer.append(")"))
return false;
c.currentPrecedence = lastPrecedence;
return true;
}
static bool
PrintExpr(WasmPrintContext& c, AstExpr& expr)
{
@ -1376,8 +1387,6 @@ PrintExpr(WasmPrintContext& c, AstExpr& expr)
return PrintNop(c);
case AstExprKind::Drop:
return PrintDrop(c, expr.as<AstDrop>());
case AstExprKind::NullaryOperator:
return PrintNullaryOperator(c, expr.as<AstNullaryOperator>());
case AstExprKind::Unreachable:
return PrintUnreachable(c, expr.as<AstUnreachable>());
case AstExprKind::Call:
@ -1418,6 +1427,10 @@ PrintExpr(WasmPrintContext& c, AstExpr& expr)
return PrintReturn(c, expr.as<AstReturn>());
case AstExprKind::First:
return PrintFirst(c, expr.as<AstFirst>());
case AstExprKind::CurrentMemory:
return PrintCurrentMemory(c, expr.as<AstCurrentMemory>());
case AstExprKind::GrowMemory:
return PrintGrowMemory(c, expr.as<AstGrowMemory>());
default:
// Note: it's important not to remove this default since readExpr()
// can return Expr values for which there is no enumerator.

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

@ -464,18 +464,25 @@ RenderFirst(WasmRenderContext& c, AstFirst& first)
}
static bool
RenderNullaryOperator(WasmRenderContext& c, AstNullaryOperator& op)
RenderCurrentMemory(WasmRenderContext& c, AstCurrentMemory& cm)
{
if (!RenderIndent(c))
return false;
const char* opStr;
switch (op.expr()) {
case Expr::CurrentMemory: opStr = "current_memory"; break;
default: return false;
}
return c.buffer.append("current_memory\n");
}
return c.buffer.append(opStr, strlen(opStr));
static bool
RenderGrowMemory(WasmRenderContext& c, AstGrowMemory& gm)
{
if (!RenderExpr(c, *gm.op()))
return false;
if (!RenderIndent(c))
return false;
MAP_AST_EXPR(c, gm);
return c.buffer.append("grow_memory\n");
}
static bool
@ -511,7 +518,6 @@ RenderUnaryOperator(WasmRenderContext& c, AstUnaryOperator& op)
case Expr::F64Nearest: opStr = "f64.nearest"; break;
case Expr::F64Sqrt: opStr = "f64.sqrt"; break;
case Expr::F64Trunc: opStr = "f64.trunc"; break;
case Expr::GrowMemory: opStr = "grow_memory"; break;
default: return false;
}
@ -1049,10 +1055,6 @@ RenderExpr(WasmRenderContext& c, AstExpr& expr, bool newLine /* = true */)
if (!RenderIf(c, expr.as<AstIf>()))
return false;
break;
case AstExprKind::NullaryOperator:
if (!RenderNullaryOperator(c, expr.as<AstNullaryOperator>()))
return false;
break;
case AstExprKind::UnaryOperator:
if (!RenderUnaryOperator(c, expr.as<AstUnaryOperator>()))
return false;
@ -1098,6 +1100,14 @@ RenderExpr(WasmRenderContext& c, AstExpr& expr, bool newLine /* = true */)
if (!RenderFirst(c, expr.as<AstFirst>()))
return false;
break;
case AstExprKind::CurrentMemory:
if (!RenderCurrentMemory(c, expr.as<AstCurrentMemory>()))
return false;
break;
case AstExprKind::GrowMemory:
if (!RenderGrowMemory(c, expr.as<AstGrowMemory>()))
return false;
break;
default:
// Note: it's important not to remove this default since readExpr()
// can return Expr values for which there is no enumerator.

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

@ -408,9 +408,9 @@ DecodeFunctionBodyExprs(FunctionDecoder& f)
case Expr::F64Store:
CHECK(f.checkHasMemory() && f.iter().readStore(ValType::F64, 8, nullptr, nullptr));
case Expr::GrowMemory:
CHECK(f.checkHasMemory() && f.iter().readUnary(ValType::I32, nullptr));
CHECK(f.checkHasMemory() && f.iter().readGrowMemory(nullptr));
case Expr::CurrentMemory:
CHECK(f.checkHasMemory() && f.iter().readNullary(ValType::I32));
CHECK(f.checkHasMemory() && f.iter().readCurrentMemory());
case Expr::Br:
CHECK(f.iter().readBr(nullptr, nullptr, nullptr));
case Expr::BrIf:

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

@ -125,6 +125,8 @@ class WasmPrintBuffer
}
template <size_t ArrayLength>
bool append(const char (&array)[ArrayLength]) {
static_assert(ArrayLength > 0, "null-terminated");
MOZ_ASSERT(array[ArrayLength - 1] == '\0');
return append(array, ArrayLength - 1);
}
char16_t getChar(size_t index) {

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

@ -3080,7 +3080,7 @@ EmitGrowMemory(FunctionCompiler& f)
return false;
MDefinition* delta;
if (!f.iter().readUnary(ValType::I32, &delta))
if (!f.iter().readGrowMemory(&delta))
return false;
if (!f.passArg(delta, ValType::I32, &args))
@ -3106,7 +3106,7 @@ EmitCurrentMemory(FunctionCompiler& f)
CallCompileState args(f, lineOrBytecode);
if (!f.iter().readNullary(ValType::I32))
if (!f.iter().readCurrentMemory())
return false;
if (!f.startCall(&args))

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

@ -78,6 +78,7 @@ class WasmToken
ComparisonOpcode,
Const,
ConversionOpcode,
CurrentMemory,
Data,
Drop,
Elem,
@ -92,6 +93,7 @@ class WasmToken
GetGlobal,
GetLocal,
Global,
GrowMemory,
If,
Import,
Index,
@ -120,7 +122,6 @@ class WasmToken
Text,
Then,
Type,
NullaryOpcode,
UnaryOpcode,
Unreachable,
UnsignedInteger,
@ -203,7 +204,7 @@ class WasmToken
MOZ_ASSERT(begin != end);
MOZ_ASSERT(kind_ == UnaryOpcode || kind_ == BinaryOpcode || kind_ == TernaryOpcode ||
kind_ == ComparisonOpcode || kind_ == ConversionOpcode ||
kind_ == Load || kind_ == Store || kind_ == NullaryOpcode);
kind_ == Load || kind_ == Store);
u.expr_ = expr;
}
explicit WasmToken(const char16_t* begin)
@ -254,7 +255,7 @@ class WasmToken
Expr expr() const {
MOZ_ASSERT(kind_ == UnaryOpcode || kind_ == BinaryOpcode || kind_ == TernaryOpcode ||
kind_ == ComparisonOpcode || kind_ == ConversionOpcode ||
kind_ == Load || kind_ == Store || kind_ == NullaryOpcode);
kind_ == Load || kind_ == Store);
return u.expr_;
}
bool isOpcode() const {
@ -269,9 +270,11 @@ class WasmToken
case ComparisonOpcode:
case Const:
case ConversionOpcode:
case CurrentMemory:
case Drop:
case GetGlobal:
case GetLocal:
case GrowMemory:
case If:
case Load:
case Loop:
@ -282,7 +285,6 @@ class WasmToken
case Store:
case TeeLocal:
case TernaryOpcode:
case NullaryOpcode:
case UnaryOpcode:
case Unreachable:
return true;
@ -854,7 +856,7 @@ WasmTokenStream::next()
return WasmToken(WasmToken::Call, begin, cur_);
}
if (consume(u"current_memory"))
return WasmToken(WasmToken::NullaryOpcode, Expr::CurrentMemory, begin, cur_);
return WasmToken(WasmToken::CurrentMemory, begin, cur_);
break;
case 'd':
@ -1091,7 +1093,7 @@ WasmTokenStream::next()
if (consume(u"global"))
return WasmToken(WasmToken::Global, begin, cur_);
if (consume(u"grow_memory"))
return WasmToken(WasmToken::UnaryOpcode, Expr::GrowMemory, begin, cur_);
return WasmToken(WasmToken::GrowMemory, begin, cur_);
break;
case 'i':
@ -1406,7 +1408,7 @@ WasmTokenStream::next()
if (consume(u"nan"))
return nan(begin);
if (consume(u"nop"))
return WasmToken(WasmToken::NullaryOpcode, Expr::Nop, begin, cur_);
return WasmToken(WasmToken::Nop, begin, cur_);
break;
case 'o':
@ -2088,12 +2090,6 @@ ParseUnaryOperator(WasmParseContext& c, Expr expr, bool inParens)
return new(c.lifo) AstUnaryOperator(expr, op);
}
static AstNullaryOperator*
ParseNullaryOperator(WasmParseContext& c, Expr expr)
{
return new(c.lifo) AstNullaryOperator(expr);
}
static AstBinaryOperator*
ParseBinaryOperator(WasmParseContext& c, Expr expr, bool inParens)
{
@ -2381,6 +2377,16 @@ ParseBranchTable(WasmParseContext& c, WasmToken brTable, bool inParens)
return new(c.lifo) AstBranchTable(*index, def, Move(table), value);
}
static AstGrowMemory*
ParseGrowMemory(WasmParseContext& c, bool inParens)
{
AstExpr* op = ParseExpr(c, inParens);
if (!op)
return nullptr;
return new(c.lifo) AstGrowMemory(op);
}
static AstExpr*
ParseExprBody(WasmParseContext& c, WasmToken token, bool inParens)
{
@ -2433,8 +2439,12 @@ ParseExprBody(WasmParseContext& c, WasmToken token, bool inParens)
return ParseTernaryOperator(c, token.expr(), inParens);
case WasmToken::UnaryOpcode:
return ParseUnaryOperator(c, token.expr(), inParens);
case WasmToken::NullaryOpcode:
return ParseNullaryOperator(c, token.expr());
case WasmToken::Nop:
return new(c.lifo) AstNop();
case WasmToken::CurrentMemory:
return new(c.lifo) AstCurrentMemory();
case WasmToken::GrowMemory:
return ParseGrowMemory(c, inParens);
default:
c.ts.generateError(token, c.error);
return nullptr;
@ -3571,6 +3581,12 @@ ResolveUnaryOperator(Resolver& r, AstUnaryOperator& b)
return ResolveExpr(r, *b.op());
}
static bool
ResolveGrowMemory(Resolver& r, AstGrowMemory& gm)
{
return ResolveExpr(r, *gm.op());
}
static bool
ResolveBinaryOperator(Resolver& r, AstBinaryOperator& b)
{
@ -3664,8 +3680,8 @@ ResolveExpr(Resolver& r, AstExpr& expr)
switch (expr.kind()) {
case AstExprKind::Nop:
case AstExprKind::Pop:
case AstExprKind::NullaryOperator:
case AstExprKind::Unreachable:
case AstExprKind::CurrentMemory:
return true;
case AstExprKind::Drop:
return ResolveDropOperator(r, expr.as<AstDrop>());
@ -3711,6 +3727,8 @@ ResolveExpr(Resolver& r, AstExpr& expr)
return ResolveTernaryOperator(r, expr.as<AstTernaryOperator>());
case AstExprKind::UnaryOperator:
return ResolveUnaryOperator(r, expr.as<AstUnaryOperator>());
case AstExprKind::GrowMemory:
return ResolveGrowMemory(r, expr.as<AstGrowMemory>());
}
MOZ_CRASH("Bad expr kind");
}
@ -3930,6 +3948,9 @@ EncodeCallIndirect(Encoder& e, AstCallIndirect& c)
if (!e.writeVarU32(c.sig().index()))
return false;
if (!e.writeVarU32(uint32_t(MemoryTableFlags::Default)))
return false;
return true;
}
@ -4007,12 +4028,6 @@ EncodeUnaryOperator(Encoder& e, AstUnaryOperator& b)
e.writeExpr(b.expr());
}
static bool
EncodeNullaryOperator(Encoder& e, AstNullaryOperator& b)
{
return e.writeExpr(b.expr());
}
static bool
EncodeBinaryOperator(Encoder& e, AstBinaryOperator& b)
{
@ -4139,6 +4154,33 @@ EncodeBranchTable(Encoder& e, AstBranchTable& bt)
return true;
}
static bool
EncodeCurrentMemory(Encoder& e, AstCurrentMemory& cm)
{
if (!e.writeExpr(Expr::CurrentMemory))
return false;
if (!e.writeVarU32(uint32_t(MemoryTableFlags::Default)))
return false;
return true;
}
static bool
EncodeGrowMemory(Encoder& e, AstGrowMemory& gm)
{
if (!EncodeExpr(e, *gm.op()))
return false;
if (!e.writeExpr(Expr::GrowMemory))
return false;
if (!e.writeVarU32(uint32_t(MemoryTableFlags::Default)))
return false;
return true;
}
static bool
EncodeExpr(Encoder& e, AstExpr& expr)
{
@ -4193,8 +4235,10 @@ EncodeExpr(Encoder& e, AstExpr& expr)
return EncodeTernaryOperator(e, expr.as<AstTernaryOperator>());
case AstExprKind::UnaryOperator:
return EncodeUnaryOperator(e, expr.as<AstUnaryOperator>());
case AstExprKind::NullaryOperator:
return EncodeNullaryOperator(e, expr.as<AstNullaryOperator>());
case AstExprKind::CurrentMemory:
return EncodeCurrentMemory(e, expr.as<AstCurrentMemory>());
case AstExprKind::GrowMemory:
return EncodeGrowMemory(e, expr.as<AstGrowMemory>());
}
MOZ_CRASH("Bad expr kind");
}