mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1242949: Implement Block in WebAssembly; r=luke
This commit is contained in:
parent
7e50fbe47b
commit
afd85313d2
@ -2768,14 +2768,6 @@ class MOZ_STACK_CLASS FunctionValidator
|
||||
return writeOp(SimdToExpr(simdType, op));
|
||||
}
|
||||
|
||||
MOZ_WARN_UNUSED_RESULT
|
||||
bool writeDebugCheckPoint() {
|
||||
#ifdef DEBUG
|
||||
return writeOp(Expr::DebugCheckPoint);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
MOZ_WARN_UNUSED_RESULT
|
||||
bool writeU8(uint8_t u8) {
|
||||
return encoder().writeU8(u8);
|
||||
@ -5704,7 +5696,7 @@ CheckComma(FunctionValidator& f, ParseNode* comma, Type* type)
|
||||
MOZ_ASSERT(comma->isKind(PNK_COMMA));
|
||||
ParseNode* operands = ListHead(comma);
|
||||
|
||||
if (!f.writeOp(Expr::Block) || !f.writeU32(ListLength(comma)))
|
||||
if (!f.writeOp(Expr::Block) || !f.writeVarU32(ListLength(comma)))
|
||||
return false;
|
||||
|
||||
ParseNode* pn = operands;
|
||||
@ -5713,8 +5705,7 @@ CheckComma(FunctionValidator& f, ParseNode* comma, Type* type)
|
||||
return false;
|
||||
}
|
||||
|
||||
return CheckExpr(f, pn, type) &&
|
||||
f.writeDebugCheckPoint();
|
||||
return CheckExpr(f, pn, type);
|
||||
}
|
||||
|
||||
static bool
|
||||
@ -6245,7 +6236,7 @@ CheckFor(FunctionValidator& f, ParseNode* forStmt)
|
||||
if (maybeInc && !CheckAsExprStatement(f, maybeInc))
|
||||
return false;
|
||||
|
||||
return f.writeDebugCheckPoint();
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
@ -6561,7 +6552,7 @@ CheckStatementList(FunctionValidator& f, ParseNode* stmtList)
|
||||
{
|
||||
MOZ_ASSERT(stmtList->isKind(PNK_STATEMENTLIST));
|
||||
|
||||
if (!f.writeOp(Expr::Block) || !f.writeU32(ListLength(stmtList)))
|
||||
if (!f.writeOp(Expr::Block) || !f.writeVarU32(ListLength(stmtList)))
|
||||
return false;
|
||||
|
||||
for (ParseNode* stmt = ListHead(stmtList); stmt; stmt = NextNode(stmt)) {
|
||||
@ -6569,7 +6560,7 @@ CheckStatementList(FunctionValidator& f, ParseNode* stmtList)
|
||||
return false;
|
||||
}
|
||||
|
||||
return f.writeDebugCheckPoint();
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
|
@ -201,6 +201,28 @@ DecodeSetLocal(FunctionDecoder& f, ExprType expected)
|
||||
return CheckType(f, localType, expected);
|
||||
}
|
||||
|
||||
static bool
|
||||
DecodeBlock(FunctionDecoder& f, ExprType expected)
|
||||
{
|
||||
uint32_t numExprs;
|
||||
if (!f.d().readVarU32(&numExprs))
|
||||
return f.fail("unable to read block's number of expressions");
|
||||
|
||||
if (numExprs) {
|
||||
for (uint32_t i = 0; i < numExprs - 1; i++) {
|
||||
if (!DecodeExpr(f, ExprType::Void))
|
||||
return false;
|
||||
}
|
||||
if (!DecodeExpr(f, expected))
|
||||
return false;
|
||||
} else {
|
||||
if (!CheckType(f, ExprType::Void, expected))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
DecodeExpr(FunctionDecoder& f, ExprType expected)
|
||||
{
|
||||
@ -217,6 +239,8 @@ DecodeExpr(FunctionDecoder& f, ExprType expected)
|
||||
return DecodeGetLocal(f, expected);
|
||||
case Expr::SetLocal:
|
||||
return DecodeSetLocal(f, expected);
|
||||
case Expr::Block:
|
||||
return DecodeBlock(f, expected);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -206,8 +206,6 @@ enum class Expr : uint16_t
|
||||
InterruptCheckHead,
|
||||
InterruptCheckLoop,
|
||||
|
||||
DebugCheckPoint,
|
||||
|
||||
I32Min,
|
||||
I32Max,
|
||||
|
||||
|
@ -267,7 +267,7 @@ ModuleGenerator::allocateGlobalVar(ValType type, bool isConst, uint32_t* index)
|
||||
void
|
||||
ModuleGenerator::initSig(uint32_t sigIndex, Sig&& sig)
|
||||
{
|
||||
MOZ_ASSERT(module_->kind == ModuleKind::AsmJS);
|
||||
MOZ_ASSERT(isAsmJS());
|
||||
MOZ_ASSERT(sigIndex == numSigs_);
|
||||
numSigs_++;
|
||||
|
||||
@ -285,7 +285,7 @@ ModuleGenerator::sig(uint32_t index) const
|
||||
bool
|
||||
ModuleGenerator::initFuncSig(uint32_t funcIndex, uint32_t sigIndex)
|
||||
{
|
||||
MOZ_ASSERT(module_->kind == ModuleKind::AsmJS);
|
||||
MOZ_ASSERT(isAsmJS());
|
||||
MOZ_ASSERT(funcIndex == module_->numFuncs);
|
||||
MOZ_ASSERT(!shared_->funcSigs[funcIndex]);
|
||||
|
||||
@ -304,7 +304,7 @@ ModuleGenerator::funcSig(uint32_t funcIndex) const
|
||||
bool
|
||||
ModuleGenerator::initImport(uint32_t importIndex, uint32_t sigIndex, uint32_t globalDataOffset)
|
||||
{
|
||||
MOZ_ASSERT(module_->kind == ModuleKind::AsmJS);
|
||||
MOZ_ASSERT(isAsmJS());
|
||||
MOZ_ASSERT(importIndex == module_->imports.length());
|
||||
if (!addImport(sig(sigIndex), globalDataOffset))
|
||||
return false;
|
||||
|
@ -166,6 +166,7 @@ class MOZ_STACK_CLASS ModuleGenerator
|
||||
|
||||
bool init(UniqueModuleGeneratorData shared, ModuleKind = ModuleKind::Wasm);
|
||||
|
||||
bool isAsmJS() const { return module_->kind == ModuleKind::AsmJS; }
|
||||
CompileArgs args() const { return module_->compileArgs; }
|
||||
jit::MacroAssembler& masm() { return masm_; }
|
||||
const Uint32Vector& funcEntryOffsets() const { return funcEntryOffsets_; }
|
||||
|
@ -1195,10 +1195,6 @@ class FunctionCompiler
|
||||
*column = sc.column;
|
||||
}
|
||||
|
||||
void assertDebugCheckPoint() {
|
||||
MOZ_ASSERT(readOpcode() == Expr::DebugCheckPoint);
|
||||
}
|
||||
|
||||
bool done() const { return decoder_.done(); }
|
||||
|
||||
/*************************************************************************/
|
||||
@ -2470,8 +2466,6 @@ EmitFor(FunctionCompiler& f, Expr expr, const LabelVector* maybeLabels)
|
||||
return false;
|
||||
}
|
||||
|
||||
f.assertDebugCheckPoint();
|
||||
|
||||
return f.closeLoop(loopEntry, afterLoop);
|
||||
}
|
||||
|
||||
@ -2635,15 +2629,16 @@ EmitRet(FunctionCompiler& f)
|
||||
static bool
|
||||
EmitBlock(FunctionCompiler& f, ExprType type, MDefinition** def)
|
||||
{
|
||||
size_t numStmt = f.readU32();
|
||||
for (size_t i = 1; i < numStmt; i++) {
|
||||
// Fine to clobber def, we only want the last use.
|
||||
if (!EmitExprStmt(f, def))
|
||||
uint32_t numStmts = f.readVarU32();
|
||||
if (numStmts) {
|
||||
for (uint32_t i = 0; i < numStmts - 1; i++) {
|
||||
// Fine to clobber def, we only want the last use.
|
||||
if (!EmitExprStmt(f, def))
|
||||
return false;
|
||||
}
|
||||
if (!EmitExpr(f, type, def))
|
||||
return false;
|
||||
}
|
||||
if (numStmt && !EmitExpr(f, type, def))
|
||||
return false;
|
||||
f.assertDebugCheckPoint();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2967,7 +2962,6 @@ EmitExpr(FunctionCompiler& f, ExprType type, MDefinition** def, LabelVector* may
|
||||
case Expr::I64StoreMem32:
|
||||
case Expr::I64StoreMem:
|
||||
MOZ_CRASH("NYI");
|
||||
case Expr::DebugCheckPoint:
|
||||
case Expr::Unreachable:
|
||||
break;
|
||||
case Expr::Limit:
|
||||
@ -3012,7 +3006,7 @@ wasm::IonCompileFunction(IonCompileTask* task)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IsVoid(f.sig().ret()))
|
||||
if (IsVoid(f.sig().ret()) || !last)
|
||||
f.returnVoid();
|
||||
else
|
||||
f.returnExpr(last);
|
||||
|
@ -77,7 +77,8 @@ class IonCompileTask
|
||||
IonCompileTask& operator=(const IonCompileTask&) = delete;
|
||||
|
||||
public:
|
||||
IonCompileTask(JSRuntime* rt, CompileArgs args, ModuleGeneratorThreadView& mg, size_t defaultChunkSize)
|
||||
IonCompileTask(JSRuntime* rt, CompileArgs args, ModuleGeneratorThreadView& mg,
|
||||
size_t defaultChunkSize)
|
||||
: runtime_(rt),
|
||||
args_(args),
|
||||
mg_(mg),
|
||||
|
@ -41,6 +41,8 @@ static const unsigned AST_LIFO_DEFAULT_CHUNK_SIZE = 4096;
|
||||
/*****************************************************************************/
|
||||
// wasm AST
|
||||
|
||||
class WasmAstExpr;
|
||||
|
||||
template <class T>
|
||||
using WasmAstVector = mozilla::Vector<T, 0, LifoAllocPolicy<Fallible>>;
|
||||
|
||||
@ -48,6 +50,7 @@ template <class K, class V, class HP>
|
||||
using WasmAstHashMap = HashMap<K, V, HP, LifoAllocPolicy<Fallible>>;
|
||||
|
||||
typedef WasmAstVector<ValType> WasmAstValTypeVector;
|
||||
typedef WasmAstVector<WasmAstExpr*> WasmAstExprVector;
|
||||
|
||||
struct WasmAstBase
|
||||
{
|
||||
@ -88,6 +91,7 @@ class WasmAstSig : public WasmAstBase
|
||||
|
||||
enum class WasmAstKind
|
||||
{
|
||||
Block,
|
||||
Const,
|
||||
Export,
|
||||
Func,
|
||||
@ -178,6 +182,20 @@ class WasmAstSetLocal : public WasmAstExpr
|
||||
}
|
||||
};
|
||||
|
||||
class WasmAstBlock : public WasmAstExpr
|
||||
{
|
||||
WasmAstExprVector exprs_;
|
||||
|
||||
public:
|
||||
static const WasmAstKind Kind = WasmAstKind::Block;
|
||||
WasmAstBlock(WasmAstExprVector&& exprs)
|
||||
: WasmAstExpr(Kind),
|
||||
exprs_(Move(exprs))
|
||||
{}
|
||||
|
||||
const WasmAstExprVector& exprs() const { return exprs_; }
|
||||
};
|
||||
|
||||
class WasmAstFunc : public WasmAstNode
|
||||
{
|
||||
const uint32_t sigIndex_;
|
||||
@ -285,6 +303,7 @@ class WasmToken
|
||||
public:
|
||||
enum Kind
|
||||
{
|
||||
Block,
|
||||
CloseParen,
|
||||
Const,
|
||||
EndOfFile,
|
||||
@ -457,6 +476,11 @@ class WasmTokenStream
|
||||
} while (*cur_++ != '"');
|
||||
return WasmToken(WasmToken::Text, begin, cur_);
|
||||
|
||||
case 'b':
|
||||
if (consume(end_, MOZ_UTF16("lock")))
|
||||
return WasmToken(WasmToken::Block, begin, cur_);
|
||||
break;
|
||||
|
||||
case '$':
|
||||
while (cur_ != end_ && IsNameAfterDollar(*cur_))
|
||||
cur_++;
|
||||
@ -571,7 +595,7 @@ class WasmTokenStream
|
||||
{}
|
||||
void generateError(WasmToken token, UniqueChars* error) {
|
||||
unsigned column = token.begin() - lineStart_ + 1;
|
||||
error->reset(JS_smprintf("parsing wasm text at at %u:%u", line_, column));
|
||||
error->reset(JS_smprintf("parsing wasm text at %u:%u", line_, column));
|
||||
}
|
||||
|
||||
WasmToken peek() {
|
||||
@ -679,6 +703,27 @@ ParseSetLocal(WasmParseContext& c)
|
||||
return new(c.lifo) WasmAstSetLocal(localIndex.integer(), *value);
|
||||
}
|
||||
|
||||
static WasmAstBlock*
|
||||
ParseBlock(WasmParseContext& c)
|
||||
{
|
||||
WasmToken numExprs;
|
||||
if (!c.ts.match(WasmToken::Integer, &numExprs, c.error))
|
||||
return nullptr;
|
||||
|
||||
WasmAstExprVector exprs(c.lifo);
|
||||
if (!exprs.reserve(numExprs.integer()))
|
||||
return nullptr;
|
||||
|
||||
for (uint32_t i = 0; i < numExprs.integer(); i++) {
|
||||
WasmAstExpr* value = ParseExpr(c);
|
||||
if (!value)
|
||||
return nullptr;
|
||||
exprs.infallibleAppend(value);
|
||||
}
|
||||
|
||||
return new(c.lifo) WasmAstBlock(Move(exprs));
|
||||
}
|
||||
|
||||
static WasmAstExpr*
|
||||
ParseExprInsideParens(WasmParseContext& c)
|
||||
{
|
||||
@ -687,6 +732,8 @@ ParseExprInsideParens(WasmParseContext& c)
|
||||
switch (expr.kind()) {
|
||||
case WasmToken::Nop:
|
||||
return new(c.lifo) WasmAstNop;
|
||||
case WasmToken::Block:
|
||||
return ParseBlock(c);
|
||||
case WasmToken::Const:
|
||||
return ParseConst(c, expr);
|
||||
case WasmToken::GetLocal:
|
||||
@ -850,6 +897,24 @@ TextToAst(const char16_t* text, LifoAlloc& lifo, UniqueChars* error)
|
||||
static bool
|
||||
EncodeExpr(Encoder& e, WasmAstExpr& expr);
|
||||
|
||||
static bool
|
||||
EncodeBlock(Encoder& e, WasmAstBlock& b)
|
||||
{
|
||||
if (!e.writeExpr(Expr::Block))
|
||||
return false;
|
||||
|
||||
size_t numExprs = b.exprs().length();
|
||||
if (!e.writeVarU32(numExprs))
|
||||
return false;
|
||||
|
||||
for (size_t i = 0; i < numExprs; i++) {
|
||||
if (!EncodeExpr(e, *b.exprs()[i]))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
EncodeConst(Encoder& e, WasmAstConst& c)
|
||||
{
|
||||
@ -884,6 +949,8 @@ EncodeExpr(Encoder& e, WasmAstExpr& expr)
|
||||
switch (expr.kind()) {
|
||||
case WasmAstKind::Nop:
|
||||
return e.writeExpr(Expr::Nop);
|
||||
case WasmAstKind::Block:
|
||||
return EncodeBlock(e, expr.as<WasmAstBlock>());
|
||||
case WasmAstKind::Const:
|
||||
return EncodeConst(e, expr.as<WasmAstConst>());
|
||||
case WasmAstKind::GetLocal:
|
||||
|
@ -126,3 +126,24 @@ assertEq(wasmEvalText('(module (func (result i32) (local i32) (set_local 0 (i32.
|
||||
assertEq(wasmEvalText('(module (func (result i32) (local i32) (set_local 0 (get_local 0))) (export "" 0))')(), 0);
|
||||
|
||||
assertErrorMessage(() => wasmEvalText('(module (func (local i64)))'), Error, /NYI/);
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// blocks
|
||||
|
||||
assertThrowsInstanceOf(() => wasmEvalText('(module (block))'), Error);
|
||||
assertThrowsInstanceOf(() => wasmEvalText('(module (block -1 (i32.const 42)))'), Error);
|
||||
assertEq(wasmEvalText('(module (func (block 0)) (export "" 0))')(), undefined);
|
||||
|
||||
assertErrorMessage(() => wasmEvalText('(module (func (result i32) (block 0)))'), Error, mismatchError("void", "i32"));
|
||||
assertErrorMessage(() => wasmEvalText('(module (func (result i32) (block 1 (block 0))))'), Error, mismatchError("void", "i32"));
|
||||
assertErrorMessage(() => wasmEvalText('(module (func (local i32) (set_local 0 (block 0))))'), Error, mismatchError("void", "i32"));
|
||||
|
||||
assertThrowsInstanceOf(() => wasmEvalText('(module (block 1))'), Error);
|
||||
assertEq(wasmEvalText('(module (func (block 1 (block 0))) (export "" 0))')(), undefined);
|
||||
assertEq(wasmEvalText('(module (func (result i32) (block 1 (i32.const 42))) (export "" 0))')(), 42);
|
||||
assertEq(wasmEvalText('(module (func (result i32) (block 1 (block 1 (i32.const 42)))) (export "" 0))')(), 42);
|
||||
assertErrorMessage(() => wasmEvalText('(module (func (result f32) (block 1 (i32.const 0))))'), Error, mismatchError("i32", "f32"));
|
||||
|
||||
assertEq(wasmEvalText('(module (func (result i32) (block 2 (i32.const 13) (block 1 (i32.const 42)))) (export "" 0))')(), 42);
|
||||
assertErrorMessage(() => wasmEvalText('(module (func (result f32) (param f32) (block 2 (get_local 0) (i32.const 0))))'), Error, mismatchError("i32", "f32"));
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user