--- a/js/src/asmjs/WasmText.cpp
+++ b/js/src/asmjs/WasmText.cpp
@@ -105,18 +105,20 @@ enum class WasmAstExprKind
BinaryOperator,
Block,
Call,
ComparisonOperator,
Const,
ConversionOperator,
GetLocal,
IfElse,
+ Load,
Nop,
SetLocal,
+ Store,
UnaryOperator,
};
class WasmAstExpr : public WasmAstNode
{
const WasmAstExprKind kind_;
protected:
@@ -240,16 +242,73 @@ class WasmAstIfElse : public WasmAstExpr
bool hasElse() const { return expr_ == Expr::IfElse; }
Expr expr() const { return expr_; }
WasmAstExpr& cond() const { return *cond_; }
WasmAstExpr& ifBody() const { return *ifBody_; }
WasmAstExpr& elseBody() const { return *elseBody_; }
};
+class WasmAstLoadStoreAddress
+{
+ WasmAstExpr* base_;
+ int32_t offset_;
+ int32_t align_;
+
+ public:
+ explicit WasmAstLoadStoreAddress(WasmAstExpr* base, int32_t offset,
+ int32_t align)
+ : base_(base),
+ offset_(offset),
+ align_(align)
+ {}
+
+ WasmAstExpr& base() const { return *base_; }
+ int32_t offset() const { return offset_; }
+ int32_t align() const { return align_; }
+};
+
+class WasmAstLoad : public WasmAstExpr
+{
+ Expr expr_;
+ WasmAstLoadStoreAddress address_;
+
+ public:
+ static const WasmAstExprKind Kind = WasmAstExprKind::Load;
+ explicit WasmAstLoad(Expr expr, const WasmAstLoadStoreAddress &address)
+ : WasmAstExpr(Kind),
+ expr_(expr),
+ address_(address)
+ {}
+
+ Expr expr() const { return expr_; }
+ const WasmAstLoadStoreAddress& address() const { return address_; }
+};
+
+class WasmAstStore : public WasmAstExpr
+{
+ Expr expr_;
+ WasmAstLoadStoreAddress address_;
+ WasmAstExpr* value_;
+
+ public:
+ static const WasmAstExprKind Kind = WasmAstExprKind::Store;
+ explicit WasmAstStore(Expr expr, const WasmAstLoadStoreAddress &address,
+ WasmAstExpr* value)
+ : WasmAstExpr(Kind),
+ expr_(expr),
+ address_(address),
+ value_(value)
+ {}
+
+ Expr expr() const { return expr_; }
+ const WasmAstLoadStoreAddress& address() const { return address_; }
+ WasmAstExpr& value() const { return *value_; }
+};
+
class WasmAstFunc : public WasmAstNode
{
const uint32_t sigIndex_;
WasmAstValTypeVector varTypes_;
WasmAstExpr* const maybeBody_;
public:
WasmAstFunc(uint32_t sigIndex, WasmAstValTypeVector&& varTypes, WasmAstExpr* maybeBody)
@@ -484,46 +543,51 @@ class WasmToken
HexNumber,
DecNumber,
Infinity,
NaN
};
enum Kind
{
+ Align,
BinaryOpcode,
Block,
Call,
CallImport,
CloseParen,
ComparisonOpcode,
Const,
ConversionOpcode,
EndOfFile,
+ Equal,
Error,
Export,
Float,
Func,
GetLocal,
If,
IfElse,
Import,
Index,
UnsignedInteger,
SignedInteger,
Memory,
+ Load,
Local,
Module,
Name,
Nop,
+ Offset,
OpenParen,
Param,
Result,
Segment,
SetLocal,
+ Store,
Text,
UnaryOpcode,
ValueType
};
private:
Kind kind_;
const char16_t* begin_;
const char16_t* end_;
@@ -589,17 +653,17 @@ class WasmToken
}
explicit WasmToken(Kind kind, Expr expr, 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_ == ConversionOpcode || kind_ == Load || kind_ == Store);
u.expr_ = expr;
}
explicit WasmToken(const char16_t* begin)
: kind_(Error),
begin_(begin),
end_(begin)
{}
Kind kind() const {
@@ -635,17 +699,17 @@ class WasmToken
return u.floatLiteralKind_;
}
ValType valueType() const {
MOZ_ASSERT(kind_ == ValueType || kind_ == Const);
return u.valueType_;
}
Expr expr() const {
MOZ_ASSERT(kind_ == UnaryOpcode || kind_ == BinaryOpcode || kind_ == ComparisonOpcode ||
- kind_ == ConversionOpcode);
+ kind_ == ConversionOpcode || kind_ == Load || kind_ == Store);
return u.expr_;
}
};
static bool
IsWasmNewLine(char16_t c)
{
return c == '\n';
@@ -941,16 +1005,20 @@ WasmToken WasmTokenStream::next()
case '(':
cur_++;
return WasmToken(WasmToken::OpenParen, begin, cur_);
case ')':
cur_++;
return WasmToken(WasmToken::CloseParen, begin, cur_);
+ case '=':
+ cur_++;
+ return WasmToken(WasmToken::Equal, begin, cur_);
+
case '+': case '-':
cur_++;
if (consume(MOZ_UTF16("infinity")))
goto infinity;
if (consume(MOZ_UTF16("nan")))
goto nan;
if (!IsWasmDigit(*cur_))
break;
@@ -997,16 +1065,21 @@ WasmToken WasmTokenStream::next()
CheckedInt<uint32_t> index = u.value();
if (index.isValid())
return WasmToken(index.value(), begin, cur_);
return WasmToken(value, begin, cur_);
}
+ case 'a':
+ if (consume(MOZ_UTF16("align")))
+ return WasmToken(WasmToken::Align, begin, cur_);
+ break;
+
case 'b':
if (consume(MOZ_UTF16("block")))
return WasmToken(WasmToken::Block, begin, cur_);
break;
case 'c':
if (consume(MOZ_UTF16("call"))) {
if (consume(MOZ_UTF16("_import")))
@@ -1070,16 +1143,18 @@ WasmToken WasmTokenStream::next()
if (consume(MOZ_UTF16("gt")))
return WasmToken(WasmToken::ComparisonOpcode, Expr::F32Gt, begin, cur_);
break;
case 'l':
if (consume(MOZ_UTF16("le")))
return WasmToken(WasmToken::ComparisonOpcode, Expr::F32Le, begin, cur_);
if (consume(MOZ_UTF16("lt")))
return WasmToken(WasmToken::ComparisonOpcode, Expr::F32Lt, begin, cur_);
+ if (consume(MOZ_UTF16("load")))
+ return WasmToken(WasmToken::Load, Expr::F32LoadMem, begin, cur_);
break;
case 'm':
if (consume(MOZ_UTF16("max")))
return WasmToken(WasmToken::BinaryOpcode, Expr::F32Max, begin, cur_);
if (consume(MOZ_UTF16("min")))
return WasmToken(WasmToken::BinaryOpcode, Expr::F32Min, begin, cur_);
if (consume(MOZ_UTF16("mul")))
return WasmToken(WasmToken::BinaryOpcode, Expr::F32Mul, begin, cur_);
@@ -1097,16 +1172,18 @@ WasmToken WasmTokenStream::next()
return WasmToken(WasmToken::ConversionOpcode, Expr::F32ReinterpretI32,
begin, cur_);
break;
case 's':
if (consume(MOZ_UTF16("sqrt")))
return WasmToken(WasmToken::UnaryOpcode, Expr::F32Sqrt, begin, cur_);
if (consume(MOZ_UTF16("sub")))
return WasmToken(WasmToken::BinaryOpcode, Expr::F32Sub, begin, cur_);
+ if (consume(MOZ_UTF16("store")))
+ return WasmToken(WasmToken::Store, Expr::F32StoreMem, begin, cur_);
break;
case 't':
if (consume(MOZ_UTF16("trunc")))
return WasmToken(WasmToken::UnaryOpcode, Expr::F32Trunc, begin, cur_);
break;
}
break;
}
@@ -1153,16 +1230,18 @@ WasmToken WasmTokenStream::next()
if (consume(MOZ_UTF16("gt")))
return WasmToken(WasmToken::ComparisonOpcode, Expr::F64Gt, begin, cur_);
break;
case 'l':
if (consume(MOZ_UTF16("le")))
return WasmToken(WasmToken::ComparisonOpcode, Expr::F64Le, begin, cur_);
if (consume(MOZ_UTF16("lt")))
return WasmToken(WasmToken::ComparisonOpcode, Expr::F64Lt, begin, cur_);
+ if (consume(MOZ_UTF16("load")))
+ return WasmToken(WasmToken::Load, Expr::F64LoadMem, begin, cur_);
break;
case 'm':
if (consume(MOZ_UTF16("max")))
return WasmToken(WasmToken::BinaryOpcode, Expr::F64Max, begin, cur_);
if (consume(MOZ_UTF16("min")))
return WasmToken(WasmToken::BinaryOpcode, Expr::F64Min, begin, cur_);
if (consume(MOZ_UTF16("mul")))
return WasmToken(WasmToken::BinaryOpcode, Expr::F64Mul, begin, cur_);
@@ -1180,16 +1259,18 @@ WasmToken WasmTokenStream::next()
return WasmToken(WasmToken::ConversionOpcode, Expr::F64PromoteF32,
begin, cur_);
break;
case 's':
if (consume(MOZ_UTF16("sqrt")))
return WasmToken(WasmToken::UnaryOpcode, Expr::F64Sqrt, begin, cur_);
if (consume(MOZ_UTF16("sub")))
return WasmToken(WasmToken::BinaryOpcode, Expr::F64Sub, begin, cur_);
+ if (consume(MOZ_UTF16("store")))
+ return WasmToken(WasmToken::Store, Expr::F64StoreMem, begin, cur_);
break;
case 't':
if (consume(MOZ_UTF16("trunc")))
return WasmToken(WasmToken::UnaryOpcode, Expr::F64Trunc, begin, cur_);
break;
}
break;
}
@@ -1244,16 +1325,29 @@ WasmToken WasmTokenStream::next()
if (consume(MOZ_UTF16("le_s")))
return WasmToken(WasmToken::ComparisonOpcode, Expr::I32LeS, begin, cur_);
if (consume(MOZ_UTF16("le_u")))
return WasmToken(WasmToken::ComparisonOpcode, Expr::I32LeU, begin, cur_);
if (consume(MOZ_UTF16("lt_s")))
return WasmToken(WasmToken::ComparisonOpcode, Expr::I32LtS, begin, cur_);
if (consume(MOZ_UTF16("lt_u")))
return WasmToken(WasmToken::ComparisonOpcode, Expr::I32LtU, begin, cur_);
+ if (consume(MOZ_UTF16("load"))) {
+ if (IsWasmSpace(*cur_))
+ return WasmToken(WasmToken::Load, Expr::I32LoadMem, begin, cur_);
+ if (consume(MOZ_UTF16("8_s")))
+ return WasmToken(WasmToken::Load, Expr::I32LoadMem8S, begin, cur_);
+ if (consume(MOZ_UTF16("8_u")))
+ return WasmToken(WasmToken::Load, Expr::I32LoadMem8U, begin, cur_);
+ if (consume(MOZ_UTF16("16_s")))
+ return WasmToken(WasmToken::Load, Expr::I32LoadMem16S, begin, cur_);
+ if (consume(MOZ_UTF16("16_u")))
+ return WasmToken(WasmToken::Load, Expr::I32LoadMem16U, begin, cur_);
+ break;
+ }
break;
case 'm':
if (consume(MOZ_UTF16("mul")))
return WasmToken(WasmToken::BinaryOpcode, Expr::I32Mul, begin, cur_);
break;
case 'n':
if (consume(MOZ_UTF16("ne")))
return WasmToken(WasmToken::ComparisonOpcode, Expr::I32Ne, begin, cur_);
@@ -1279,16 +1373,25 @@ WasmToken WasmTokenStream::next()
if (consume(MOZ_UTF16("sub")))
return WasmToken(WasmToken::BinaryOpcode, Expr::I32Sub, begin, cur_);
if (consume(MOZ_UTF16("shl")))
return WasmToken(WasmToken::BinaryOpcode, Expr::I32Shl, begin, cur_);
if (consume(MOZ_UTF16("shr_s")))
return WasmToken(WasmToken::BinaryOpcode, Expr::I32ShrS, begin, cur_);
if (consume(MOZ_UTF16("shr_u")))
return WasmToken(WasmToken::BinaryOpcode, Expr::I32ShrU, begin, cur_);
+ if (consume(MOZ_UTF16("store"))) {
+ if (IsWasmSpace(*cur_))
+ return WasmToken(WasmToken::Store, Expr::I32StoreMem, begin, cur_);
+ if (consume(MOZ_UTF16("8")))
+ return WasmToken(WasmToken::Store, Expr::I32StoreMem8, begin, cur_);
+ if (consume(MOZ_UTF16("16")))
+ return WasmToken(WasmToken::Store, Expr::I32StoreMem16, begin, cur_);
+ break;
+ }
break;
case 't':
if (consume(MOZ_UTF16("trunc_s/f32")))
return WasmToken(WasmToken::ConversionOpcode, Expr::I32TruncSF32,
begin, cur_);
if (consume(MOZ_UTF16("trunc_s/f64")))
return WasmToken(WasmToken::ConversionOpcode, Expr::I32TruncSF64,
begin, cur_);
@@ -1360,16 +1463,33 @@ WasmToken WasmTokenStream::next()
if (consume(MOZ_UTF16("le_s")))
return WasmToken(WasmToken::ComparisonOpcode, Expr::I64LeS, begin, cur_);
if (consume(MOZ_UTF16("le_u")))
return WasmToken(WasmToken::ComparisonOpcode, Expr::I64LeU, begin, cur_);
if (consume(MOZ_UTF16("lt_s")))
return WasmToken(WasmToken::ComparisonOpcode, Expr::I64LtS, begin, cur_);
if (consume(MOZ_UTF16("lt_u")))
return WasmToken(WasmToken::ComparisonOpcode, Expr::I64LtU, begin, cur_);
+ if (consume(MOZ_UTF16("load"))) {
+ if (IsWasmSpace(*cur_))
+ return WasmToken(WasmToken::Load, Expr::I64LoadMem, begin, cur_);
+ if (consume(MOZ_UTF16("8_s")))
+ return WasmToken(WasmToken::Load, Expr::I64LoadMem8S, begin, cur_);
+ if (consume(MOZ_UTF16("8_u")))
+ return WasmToken(WasmToken::Load, Expr::I64LoadMem8U, begin, cur_);
+ if (consume(MOZ_UTF16("16_s")))
+ return WasmToken(WasmToken::Load, Expr::I64LoadMem16S, begin, cur_);
+ if (consume(MOZ_UTF16("16_u")))
+ return WasmToken(WasmToken::Load, Expr::I64LoadMem16U, begin, cur_);
+ if (consume(MOZ_UTF16("32_s")))
+ return WasmToken(WasmToken::Load, Expr::I64LoadMem32S, begin, cur_);
+ if (consume(MOZ_UTF16("32_u")))
+ return WasmToken(WasmToken::Load, Expr::I64LoadMem32U, begin, cur_);
+ break;
+ }
break;
case 'm':
if (consume(MOZ_UTF16("mul")))
return WasmToken(WasmToken::BinaryOpcode, Expr::I64Mul, begin, cur_);
break;
case 'n':
if (consume(MOZ_UTF16("ne")))
return WasmToken(WasmToken::ComparisonOpcode, Expr::I64Ne, begin, cur_);
@@ -1395,16 +1515,27 @@ WasmToken WasmTokenStream::next()
if (consume(MOZ_UTF16("sub")))
return WasmToken(WasmToken::BinaryOpcode, Expr::I64Sub, begin, cur_);
if (consume(MOZ_UTF16("shl")))
return WasmToken(WasmToken::BinaryOpcode, Expr::I64Shl, begin, cur_);
if (consume(MOZ_UTF16("shr_s")))
return WasmToken(WasmToken::BinaryOpcode, Expr::I64ShrS, begin, cur_);
if (consume(MOZ_UTF16("shr_u")))
return WasmToken(WasmToken::BinaryOpcode, Expr::I64ShrU, begin, cur_);
+ if (consume(MOZ_UTF16("store"))) {
+ if (IsWasmSpace(*cur_))
+ return WasmToken(WasmToken::Store, Expr::I64StoreMem, begin, cur_);
+ if (consume(MOZ_UTF16("8")))
+ return WasmToken(WasmToken::Store, Expr::I64StoreMem8, begin, cur_);
+ if (consume(MOZ_UTF16("16")))
+ return WasmToken(WasmToken::Store, Expr::I64StoreMem16, begin, cur_);
+ if (consume(MOZ_UTF16("32")))
+ return WasmToken(WasmToken::Store, Expr::I64StoreMem32, begin, cur_);
+ break;
+ }
break;
case 't':
if (consume(MOZ_UTF16("trunc_s/f32")))
return WasmToken(WasmToken::ConversionOpcode, Expr::I64TruncSF32,
begin, cur_);
if (consume(MOZ_UTF16("trunc_s/f64")))
return WasmToken(WasmToken::ConversionOpcode, Expr::I64TruncSF64,
begin, cur_);
@@ -1458,16 +1589,21 @@ WasmToken WasmTokenStream::next()
cur_++;
}
return WasmToken(WasmToken::NaN, begin, cur_);
}
if (consume(MOZ_UTF16("nop")))
return WasmToken(WasmToken::Nop, begin, cur_);
break;
+ case 'o':
+ if (consume(MOZ_UTF16("offset")))
+ return WasmToken(WasmToken::Offset, begin, cur_);
+ break;
+
case 'p':
if (consume(MOZ_UTF16("param")))
return WasmToken(WasmToken::Param, begin, cur_);
break;
case 'r':
if (consume(MOZ_UTF16("result")))
return WasmToken(WasmToken::Result, begin, cur_);
@@ -1766,37 +1902,42 @@ ParseFloatLiteral(WasmParseContext& c, W
if (*cur == '-' || *cur == '+')
isNegated = *cur++ == '-';
switch (token.floatLiteralKind()) {
case WasmToken::Infinity:
*result = PositiveInfinity<Float>();
break;
case WasmToken::NaN:
- if (!ParseNaNLiteral(cur, end, result))
+ if (!ParseNaNLiteral(cur, end, result)) {
+ c.ts.generateError(token, c.error);
return false;
+ }
break;
case WasmToken::HexNumber:
- if (!ParseHexFloatLiteral(cur, end, result))
+ if (!ParseHexFloatLiteral(cur, end, result)) {
+ c.ts.generateError(token, c.error);
return false;
+ }
break;
case WasmToken::DecNumber: {
// Call into JS' strtod. Tokenization has already required that the
// string is well-behaved.
LifoAlloc::Mark mark = c.lifo.mark();
char* buffer = c.lifo.newArray<char>(end - begin + 1);
if (!buffer)
return false;
for (ptrdiff_t i = 0; i < end - cur; ++i)
buffer[i] = char(cur[i]);
char* strtod_end;
int err;
Float d = (Float)js_strtod_harder(c.dtoaState, buffer, &strtod_end, &err);
if (err != 0 || strtod_end == buffer) {
c.lifo.release(mark);
+ c.ts.generateError(token, c.error);
return false;
}
c.lifo.release(mark);
*result = d;
break;
}
}
@@ -1810,64 +1951,61 @@ static WasmAstConst*
ParseConst(WasmParseContext& c, WasmToken constToken)
{
WasmToken val = c.ts.get();
switch (constToken.valueType()) {
case ValType::I32: {
switch (val.kind()) {
case WasmToken::Index:
return new(c.lifo) WasmAstConst(Val(val.index()));
- case WasmToken::UnsignedInteger: {
- CheckedInt<uint32_t> uint = val.uint();
- if (uint.isValid())
- return new(c.lifo) WasmAstConst(Val(uint.value()));
- return nullptr;
- }
case WasmToken::SignedInteger: {
CheckedInt<int32_t> sint = val.sint();
- if (sint.isValid())
- return new(c.lifo) WasmAstConst(Val(uint32_t(sint.value())));
- return nullptr;
+ if (!sint.isValid())
+ break;
+ return new(c.lifo) WasmAstConst(Val(uint32_t(sint.value())));
}
default:
- return nullptr;
+ break;
}
+ break;
}
case ValType::I64: {
switch (val.kind()) {
case WasmToken::Index:
return new(c.lifo) WasmAstConst(Val(val.index()));
case WasmToken::UnsignedInteger:
return new(c.lifo) WasmAstConst(Val(val.uint()));
case WasmToken::SignedInteger:
return new(c.lifo) WasmAstConst(Val(uint64_t(val.sint())));
default:
- return nullptr;
+ break;
}
+ break;
}
case ValType::F32: {
if (val.kind() != WasmToken::Float)
- return nullptr;
+ break;
float result;
if (!ParseFloatLiteral(c, val, &result))
- return nullptr;
+ break;
return new(c.lifo) WasmAstConst(Val(result));
}
case ValType::F64: {
if (val.kind() != WasmToken::Float)
- return nullptr;
+ break;
double result;
if (!ParseFloatLiteral(c, val, &result))
- return nullptr;
+ break;
return new(c.lifo) WasmAstConst(Val(result));
}
default:
- c.ts.generateError(constToken, c.error);
- return nullptr;
+ break;
}
+ c.ts.generateError(constToken, c.error);
+ return nullptr;
}
static WasmAstGetLocal*
ParseGetLocal(WasmParseContext& c)
{
WasmToken localIndex;
if (!c.ts.match(WasmToken::Index, &localIndex, c.error))
return nullptr;
@@ -1953,16 +2091,145 @@ ParseIfElse(WasmParseContext& c, Expr ex
elseBody = ParseExpr(c);
if (!elseBody)
return nullptr;
}
return new(c.lifo) WasmAstIfElse(expr, cond, ifBody, elseBody);
}
+static bool
+ParseLoadStoreAddress(WasmParseContext& c, WasmAstExpr** base,
+ int32_t* offset, int32_t* align)
+{
+ *base = ParseExpr(c);
+ if (!*base)
+ return false;
+
+ WasmToken token = c.ts.get();
+
+ *offset = 0;
+ if (token.kind() == WasmToken::Offset) {
+ if (!c.ts.match(WasmToken::Equal, c.error))
+ return false;
+ WasmToken val = c.ts.get();
+ switch (val.kind()) {
+ case WasmToken::Index:
+ *offset = val.index();
+ break;
+ default:
+ c.ts.generateError(val, c.error);
+ return false;
+ }
+
+ token = c.ts.get();
+ }
+
+ *align = 0;
+ if (token.kind() == WasmToken::Align) {
+ if (!c.ts.match(WasmToken::Equal, c.error))
+ return false;
+ WasmToken val = c.ts.get();
+ switch (val.kind()) {
+ case WasmToken::Index:
+ *align = val.index();
+ break;
+ default:
+ c.ts.generateError(val, c.error);
+ return false;
+ }
+
+ token = c.ts.get();
+ }
+
+ c.ts.unget(token);
+ return true;
+}
+
+static WasmAstLoad*
+ParseLoad(WasmParseContext& c, Expr expr)
+{
+ WasmAstExpr* base;
+ int32_t offset;
+ int32_t align;
+ if (!ParseLoadStoreAddress(c, &base, &offset, &align))
+ return nullptr;
+
+ if (align == 0) {
+ switch (expr) {
+ case Expr::I32LoadMem8S:
+ case Expr::I32LoadMem8U:
+ case Expr::I64LoadMem8S:
+ case Expr::I64LoadMem8U:
+ align = 1;
+ break;
+ case Expr::I32LoadMem16S:
+ case Expr::I32LoadMem16U:
+ case Expr::I64LoadMem16S:
+ case Expr::I64LoadMem16U:
+ align = 2;
+ break;
+ case Expr::I32LoadMem:
+ case Expr::F32LoadMem:
+ case Expr::I64LoadMem32S:
+ case Expr::I64LoadMem32U:
+ align = 4;
+ break;
+ case Expr::I64LoadMem:
+ case Expr::F64LoadMem:
+ align = 8;
+ break;
+ default:
+ MOZ_CRASH("Bad load expr");
+ }
+ }
+
+ return new(c.lifo) WasmAstLoad(expr, WasmAstLoadStoreAddress(base, offset, align));
+}
+
+static WasmAstStore*
+ParseStore(WasmParseContext& c, Expr expr)
+{
+ WasmAstExpr* base;
+ int32_t offset;
+ int32_t align;
+ if (!ParseLoadStoreAddress(c, &base, &offset, &align))
+ return nullptr;
+
+ if (align == 0) {
+ switch (expr) {
+ case Expr::I32StoreMem8:
+ case Expr::I64StoreMem8:
+ align = 1;
+ break;
+ case Expr::I32StoreMem16:
+ case Expr::I64StoreMem16:
+ align = 2;
+ break;
+ case Expr::I32StoreMem:
+ case Expr::F32StoreMem:
+ case Expr::I64StoreMem32:
+ align = 4;
+ break;
+ case Expr::I64StoreMem:
+ case Expr::F64StoreMem:
+ align = 8;
+ break;
+ default:
+ MOZ_CRASH("Bad load expr");
+ }
+ }
+
+ WasmAstExpr* value = ParseExpr(c);
+ if (!value)
+ return nullptr;
+
+ return new(c.lifo) WasmAstStore(expr, WasmAstLoadStoreAddress(base, offset, align), value);
+}
+
static WasmAstExpr*
ParseExprInsideParens(WasmParseContext& c)
{
WasmToken token = c.ts.get();
switch (token.kind()) {
case WasmToken::Nop:
return new(c.lifo) WasmAstNop;
@@ -1981,18 +2248,22 @@ ParseExprInsideParens(WasmParseContext&
case WasmToken::ConversionOpcode:
return ParseConversionOperator(c, token.expr());
case WasmToken::If:
return ParseIfElse(c, Expr::If);
case WasmToken::IfElse:
return ParseIfElse(c, Expr::IfElse);
case WasmToken::GetLocal:
return ParseGetLocal(c);
+ case WasmToken::Load:
+ return ParseLoad(c, token.expr());
case WasmToken::SetLocal:
return ParseSetLocal(c);
+ case WasmToken::Store:
+ return ParseStore(c, token.expr());
case WasmToken::UnaryOpcode:
return ParseUnaryOperator(c, token.expr());
default:
c.ts.generateError(token, c.error);
return nullptr;
}
}
@@ -2337,16 +2608,39 @@ EncodeIfElse(Encoder& e, WasmAstIfElse&
{
return e.writeExpr(ie.expr()) &&
EncodeExpr(e, ie.cond()) &&
EncodeExpr(e, ie.ifBody()) &&
(!ie.hasElse() || EncodeExpr(e, ie.elseBody()));
}
static bool
+EncodeLoadStoreAddress(Encoder &e, const WasmAstLoadStoreAddress &address)
+{
+ return EncodeExpr(e, address.base()) &&
+ e.writeVarU32(address.offset()) &&
+ e.writeVarU32(address.align());
+}
+
+static bool
+EncodeLoad(Encoder& e, WasmAstLoad& l)
+{
+ return e.writeExpr(l.expr()) &&
+ EncodeLoadStoreAddress(e, l.address());
+}
+
+static bool
+EncodeStore(Encoder& e, WasmAstStore& s)
+{
+ return e.writeExpr(s.expr()) &&
+ EncodeLoadStoreAddress(e, s.address()) &&
+ EncodeExpr(e, s.value());
+}
+
+static bool
EncodeExpr(Encoder& e, WasmAstExpr& expr)
{
switch (expr.kind()) {
case WasmAstExprKind::Nop:
return e.writeExpr(Expr::Nop);
case WasmAstExprKind::BinaryOperator:
return EncodeBinaryOperator(e, expr.as<WasmAstBinaryOperator>());
case WasmAstExprKind::Block:
@@ -2358,18 +2652,22 @@ EncodeExpr(Encoder& e, WasmAstExpr& expr
case WasmAstExprKind::Const:
return EncodeConst(e, expr.as<WasmAstConst>());
case WasmAstExprKind::ConversionOperator:
return EncodeConversionOperator(e, expr.as<WasmAstConversionOperator>());
case WasmAstExprKind::GetLocal:
return EncodeGetLocal(e, expr.as<WasmAstGetLocal>());
case WasmAstExprKind::IfElse:
return EncodeIfElse(e, expr.as<WasmAstIfElse>());
+ case WasmAstExprKind::Load:
+ return EncodeLoad(e, expr.as<WasmAstLoad>());
case WasmAstExprKind::SetLocal:
return EncodeSetLocal(e, expr.as<WasmAstSetLocal>());
+ case WasmAstExprKind::Store:
+ return EncodeStore(e, expr.as<WasmAstStore>());
case WasmAstExprKind::UnaryOperator:
return EncodeUnaryOperator(e, expr.as<WasmAstUnaryOperator>());
default:;
}
MOZ_CRASH("Bad expr kind");
}
/*****************************************************************************/
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/basic-memory.js
@@ -0,0 +1,111 @@
+load(libdir + "wasm.js");
+
+quit(); // TODO: Loads and stores are NYI.
+
+if (!wasmIsSupported())
+ quit();
+
+function mismatchError(actual, expect) {
+ var str = "type mismatch: expression has type " + actual + " but expected " + expect;
+ return RegExp(str);
+}
+
+function testLoad(type, ext, base, offset, align, expect) {
+ print('(module' +
+ ' (memory 0x10000' +
+ ' (segment 0 "\\00\\01\\02\\03\\04\\05\\06\\07\\08\\09\\0a\\0b\\0c\\0d\\0e\\0f")' +
+ ' (segment 16 "\\f0\\f1\\f2\\f3\\f4\\f5\\f6\\f7\\f8\\f9\\fa\\fb\\fc\\fd\\fe\\ff")' +
+ ' )' +
+ ' (func (param i32) (result ' + type + ')' +
+ ' (' + type + '.load' + ext + ' (get_local 0)' +
+ ' offset=' + offset +
+ ' ' + (align != 0 ? 'align=' + align : '') +
+ ' )' +
+ ' ) (export "" 0))');
+ assertEq(wasmEvalText(
+ '(module' +
+ ' (memory 0x10000' +
+ ' (segment 0 "\\00\\01\\02\\03\\04\\05\\06\\07\\08\\09\\0a\\0b\\0c\\0d\\0e\\0f")' +
+ ' (segment 16 "\\f0\\f1\\f2\\f3\\f4\\f5\\f6\\f7\\f8\\f9\\fa\\fb\\fc\\fd\\fe\\ff")' +
+ ' )' +
+ ' (func (param i32) (result ' + type + ')' +
+ ' (' + type + '.load' + ext + ' (get_local 0)' +
+ ' offset=' + offset +
+ ' ' + (align != 0 ? 'align=' + align : '') +
+ ' )' +
+ ' ) (export "" 0))'
+ )(base), expect);
+}
+
+function testStore(type, ext, base, offset, align, value) {
+ assertEq(wasmEvalText(
+ '(module' +
+ ' (memory 0x10000)' +
+ ' (segment 0 "\\00\\01\\02\\03\\04\\05\\06\\07\\08\\09\\0a\\0b\\0c\\0d\\0e\\0f")' +
+ ' (segment 16 "\\f0\\f1\\f2\\f3\\f4\\f5\\f6\\f7\\f8\\f9\\fa\\fb\\fc\\fd\\fe\\ff")' +
+ ' )' +
+ ' (func (param i32) (param ' + type + ') (result ' + type + ')' +
+ ' (' + type + '.store' + ext + ' (get_local 0)' +
+ ' offset=' + offset +
+ ' ' + (align != 0 ? 'align=' + align : '') +
+ ' (get_local 1)' +
+ ' )' +
+ ' ) (export "" 0))'
+ )(base, value), value);
+}
+
+function testConstError(type, str) {
+ // For now at least, we don't distinguish between parse errors and OOMs.
+ assertErrorMessage(() => wasmEvalText('(module (func (result ' + type + ') (' + type + '.const ' + str + ')) (export "" 0))')(), Error, /out of memory/);
+}
+
+testLoad('i32', '', 0, 0, 0, 0x00010203);
+testLoad('i32', '', 1, 0, 0, 0x01020304);
+//testLoad('i32', '', 0, 1, 0, 0x01020304); // TODO: NYI
+//testLoad('i32', '', 1, 1, 4, 0x02030405); // TODO: NYI
+//testLoad('i64', '', 0, 0, 0, 0x0001020304050607); // TODO: NYI
+//testLoad('i64', '', 1, 0, 0, 0x0102030405060708); // TODO: NYI
+//testLoad('i64', '', 0, 1, 0, 0x0102030405060708); // TODO: NYI
+//testLoad('i64', '', 1, 1, 4, 0x0203040506070809); // TODO: NYI
+testLoad('f32', '', 0, 0, 0, 0x00010203);
+testLoad('f32', '', 1, 0, 0, 0x01020304);
+//testLoad('f32', '', 0, 1, 0, 0x01020304); // TODO: NYI
+//testLoad('f32', '', 1, 1, 4, 0x02030405); // TODO: NYI
+testLoad('f64', '', 0, 0, 0, 0x00010203);
+testLoad('f64', '', 1, 0, 0, 0x01020304);
+//testLoad('f64', '', 0, 1, 0, 0x01020304); // TODO: NYI
+//testLoad('f64', '', 1, 1, 4, 0x02030405); // TODO: NYI
+
+testLoad('i32', '8_s', 16, 0, 0, -0x8);
+testLoad('i32', '8_u', 16, 0, 0, 0x8);
+testLoad('i32', '16_s', 16, 0, 0, -0x707);
+testLoad('i32', '16_u', 16, 0, 0, 0x8f9);
+testLoad('i64', '8_s', 16, 0, 0, -0x8);
+testLoad('i64', '8_u', 16, 0, 0, 0x8);
+//testLoad('i64', '16_s', 16, 0, 0, -0x707); // TODO: NYI
+//testLoad('i64', '16_u', 16, 0, 0, 0x8f9); // TODO: NYI
+//testLoad('i64', '32_s', 16, 0, 0, -0x7060505); // TODO: NYI
+//testLoad('i64', '32_u', 16, 0, 0, 0x8f9fafb); // TODO: NYI
+
+testStore('i32', '', 0, 0, 0, 0xc0c1d3d4);
+testStore('i32', '', 1, 0, 0, 0xc0c1d3d4);
+//testStore('i32', '', 0, 1, 0, 0xc0c1d3d4); // TODO: NYI
+//testStore('i32', '', 1, 1, 4, 0xc0c1d3d4); // TODO: NYI
+//testStore('i64', '', 0, 0, 0, 0xc0c1d3d4e6e7090a); // TODO: NYI
+//testStore('i64', '', 1, 0, 0, 0xc0c1d3d4e6e7090a); // TODO: NYI
+//testStore('i64', '', 0, 1, 0, 0xc0c1d3d4e6e7090a); // TODO: NYI
+//testStore('i64', '', 1, 1, 4, 0xc0c1d3d4e6e7090a); // TODO: NYI
+testStore('f32', '', 0, 0, 0, 0.01234567);
+testStore('f32', '', 1, 0, 0, 0.01234567);
+//testStore('f32', '', 0, 1, 0, 0.01234567); // TODO: NYI
+//testStore('f32', '', 1, 1, 4, 0.01234567); // TODO: NYI
+testStore('f64', '', 0, 0, 0, 0.89012345);
+testStore('f64', '', 1, 0, 0, 0.89012345);
+//testStore('f64', '', 0, 1, 0, 0.89012345); // TODO: NYI
+//testStore('f64', '', 1, 1, 4, 0.89012345); // TODO: NYI
+
+testStore('i32', '8', 0, 0, 0, 0x23);
+testStore('i32', '16', 0, 0, 0, 0x2345);
+//testStore('i64', '8', 0, 0, 0, 0x23); // TODO: NYI
+//testStore('i64', '16', 0, 0, 0, 0x23); // TODO: NYI
+//testStore('i64', '32', 0, 0, 0, 0x23); // TODO: NYI