Bug 1243633 - Baldr: add call/call_import (r=bbouvier)

This commit is contained in:
Luke Wagner 2016-01-28 11:51:39 -06:00
parent c35dacbaec
commit 6d10e98724
4 changed files with 155 additions and 3 deletions

View File

@ -161,6 +161,46 @@ DecodeExprType(JSContext* cx, Decoder& d, ExprType *type)
return true;
}
static bool
DecodeCall(FunctionDecoder& f, ExprType expected)
{
uint32_t funcIndex;
if (!f.d().readU32(&funcIndex))
return f.fail("unable to read import index");
if (funcIndex >= f.mg().numFuncSigs())
return f.fail("callee index out of range");
const DeclaredSig& sig = f.mg().funcSig(funcIndex);
for (ValType argType : sig.args()) {
if (!DecodeExpr(f, ToExprType(argType)))
return false;
}
return CheckType(f, sig.ret(), expected);
}
static bool
DecodeCallImport(FunctionDecoder& f, ExprType expected)
{
uint32_t importIndex;
if (!f.d().readU32(&importIndex))
return f.fail("unable to read import index");
if (importIndex >= f.mg().numImports())
return f.fail("import index out of range");
const DeclaredSig& sig = *f.mg().import(importIndex).sig;
for (ValType argType : sig.args()) {
if (!DecodeExpr(f, ToExprType(argType)))
return false;
}
return CheckType(f, sig.ret(), expected);
}
static bool
DecodeConst(FunctionDecoder& f, ExprType expected)
{
@ -233,6 +273,10 @@ DecodeExpr(FunctionDecoder& f, ExprType expected)
switch (expr) {
case Expr::Nop:
return CheckType(f, ExprType::Void, expected);
case Expr::Call:
return DecodeCall(f, expected);
case Expr::CallImport:
return DecodeCallImport(f, expected);
case Expr::I32Const:
return DecodeConst(f, expected);
case Expr::GetLocal:

View File

@ -91,6 +91,7 @@ class WasmAstSig : public WasmAstBase
enum class WasmAstKind
{
Block,
Call,
Const,
Export,
Func,
@ -196,6 +197,23 @@ class WasmAstBlock : public WasmAstExpr
const WasmAstExprVector& exprs() const { return exprs_; }
};
class WasmAstCall : public WasmAstExpr
{
Expr expr_;
uint32_t index_;
WasmAstExprVector args_;
public:
static const WasmAstKind Kind = WasmAstKind::Call;
WasmAstCall(Expr expr, uint32_t index, WasmAstExprVector&& args)
: WasmAstExpr(Kind), expr_(expr), index_(index), args_(Move(args))
{}
Expr expr() const { return expr_; }
uint32_t index() const { return index_; }
const WasmAstExprVector& args() const { return args_; }
};
class WasmAstFunc : public WasmAstNode
{
const uint32_t sigIndex_;
@ -312,6 +330,8 @@ class WasmToken
enum Kind
{
Block,
Call,
CallImport,
CloseParen,
Const,
EndOfFile,
@ -511,6 +531,14 @@ class WasmTokenStream
return WasmToken(WasmToken::Block, begin, cur_);
break;
case 'c':
if (consume(end_, MOZ_UTF16("all"))) {
if (consume(end_, MOZ_UTF16("_import")))
return WasmToken(WasmToken::CallImport, begin, cur_);
return WasmToken(WasmToken::Call, begin, cur_);
}
break;
case 'e':
if (consume(end_, MOZ_UTF16("xport")))
return WasmToken(WasmToken::Export, begin, cur_);
@ -699,6 +727,25 @@ ParseBlock(WasmParseContext& c)
return new(c.lifo) WasmAstBlock(Move(exprs));
}
static WasmAstCall*
ParseCall(WasmParseContext& c, Expr expr)
{
WasmToken index;
if (!c.ts.match(WasmToken::Integer, &index, c.error))
return nullptr;
WasmAstExprVector args(c.lifo);
while (c.ts.getIf(WasmToken::OpenParen)) {
WasmAstExpr* arg = ParseExprInsideParens(c);
if (!arg || !args.append(arg))
return nullptr;
if (!c.ts.match(WasmToken::CloseParen, c.error))
return nullptr;
}
return new(c.lifo) WasmAstCall(expr, index.integer(), Move(args));
}
static WasmAstConst*
ParseConst(WasmParseContext& c, WasmToken constToken)
{
@ -749,6 +796,10 @@ ParseExprInsideParens(WasmParseContext& c)
return new(c.lifo) WasmAstNop;
case WasmToken::Block:
return ParseBlock(c);
case WasmToken::Call:
return ParseCall(c, Expr::Call);
case WasmToken::CallImport:
return ParseCall(c, Expr::CallImport);
case WasmToken::Const:
return ParseConst(c, expr);
case WasmToken::GetLocal:
@ -957,6 +1008,23 @@ EncodeBlock(Encoder& e, WasmAstBlock& b)
return true;
}
static bool
EncodeCall(Encoder& e, WasmAstCall& c)
{
if (!e.writeExpr(c.expr()))
return false;
if (!e.writeU32(c.index()))
return false;
for (WasmAstExpr* arg : c.args()) {
if (!EncodeExpr(e, *arg))
return false;
}
return true;
}
static bool
EncodeConst(Encoder& e, WasmAstConst& c)
{
@ -993,6 +1061,8 @@ EncodeExpr(Encoder& e, WasmAstExpr& expr)
return e.writeExpr(Expr::Nop);
case WasmAstKind::Block:
return EncodeBlock(e, expr.as<WasmAstBlock>());
case WasmAstKind::Call:
return EncodeCall(e, expr.as<WasmAstCall>());
case WasmAstKind::Const:
return EncodeConst(e, expr.as<WasmAstConst>());
case WasmAstKind::GetLocal:

View File

@ -28,13 +28,10 @@ assertEq(stack.functionDisplayName, "tester");
assertEq(stack.parent.functionDisplayName, "doTest");
assertEq(stack.parent.line, 6);
assertEq(stack.parent.column, 5);
assertEq(stack.parent.parent.functionDisplayName, "test");
assertEq(stack.parent.parent.line, 10);
assertEq(stack.parent.parent.column, 5);
assertEq(stack.parent.parent.parent.line, 24);
assertEq(stack.parent.parent.parent.column, 1);
assertEq(stack.parent.parent.parent.parent, null);

View File

@ -175,3 +175,44 @@ assertErrorMessage(() => wasmEvalText('(module (func (result f32) (block (i32.co
assertEq(wasmEvalText('(module (func (result i32) (block (i32.const 13) (block (i32.const 42)))) (export "" 0))')(), 42);
assertErrorMessage(() => wasmEvalText('(module (func (result f32) (param f32) (block (get_local 0) (i32.const 0))))'), TypeError, mismatchError("i32", "f32"));
// ----------------------------------------------------------------------------
// calls
assertThrowsInstanceOf(() => wasmEvalText('(module (func (nop)) (func (call 0 (i32.const 0))))'), TypeError);
assertThrowsInstanceOf(() => wasmEvalText('(module (func (param i32) (nop)) (func (call 0)))'), TypeError);
assertThrowsInstanceOf(() => wasmEvalText('(module (func (param f32) (nop)) (func (call 0 (i32.const 0))))'), TypeError);
assertErrorMessage(() => wasmEvalText('(module (func (nop)) (func (call 3)))'), TypeError, /callee index out of range/);
wasmEvalText('(module (func (nop)) (func (call 0)))');
wasmEvalText('(module (func (param i32) (nop)) (func (call 0 (i32.const 0))))');
assertEq(wasmEvalText('(module (func (result i32) (i32.const 42)) (func (result i32) (call 0)) (export "" 1))')(), 42);
assertThrowsInstanceOf(() => wasmEvalText('(module (func (call 0)) (export "" 0))')(), InternalError);
assertThrowsInstanceOf(() => wasmEvalText('(module (func (call 1)) (func (call 0)) (export "" 0))')(), InternalError);
assertThrowsInstanceOf(() => wasmEvalText('(module (import "a" "") (func (call_import 0 (i32.const 0))))', {a:()=>{}}), TypeError);
assertThrowsInstanceOf(() => wasmEvalText('(module (import "a" "" (param i32)) (func (call_import 0)))', {a:()=>{}}), TypeError);
assertThrowsInstanceOf(() => wasmEvalText('(module (import "a" "" (param f32)) (func (call_import 0 (i32.const 0))))', {a:()=>{}}), TypeError);
assertErrorMessage(() => wasmEvalText('(module (import "a" "") (func (call_import 1)))'), TypeError, /import index out of range/);
wasmEvalText('(module (import "a" "") (func (call_import 0)))', {a:()=>{}});
wasmEvalText('(module (import "a" "" (param i32)) (func (call_import 0 (i32.const 0))))', {a:()=>{}});
var f = wasmEvalText('(module (import "inc" "") (func (call_import 0)) (export "" 0))', {inc:()=>counter++});
var g = wasmEvalText('(module (import "f" "") (func (block (call_import 0) (call_import 0))) (export "" 0))', {f});
var counter = 0;
f();
assertEq(counter, 1);
g();
assertEq(counter, 3);
var f = wasmEvalText('(module (import "callf" "") (func (call_import 0)) (export "" 0))', {callf:()=>f()});
assertThrowsInstanceOf(() => f(), InternalError);
var f = wasmEvalText('(module (import "callg" "") (func (call_import 0)) (export "" 0))', {callg:()=>g()});
var g = wasmEvalText('(module (import "callf" "") (func (call_import 0)) (export "" 0))', {callf:()=>f()});
assertThrowsInstanceOf(() => f(), InternalError);
var code = '(module (import "one" "" (result i32)) (import "two" "" (result i32)) (func (result i32) (i32.const 3)) (func (result i32) (i32.const 4)) (func (result i32) BODY) (export "" 2))';
var imports = {one:()=>1, two:()=>2};
assertEq(wasmEvalText(code.replace('BODY', '(call_import 0)'), imports)(), 1);
assertEq(wasmEvalText(code.replace('BODY', '(call_import 1)'), imports)(), 2);
assertEq(wasmEvalText(code.replace('BODY', '(call 0)'), imports)(), 3);
assertEq(wasmEvalText(code.replace('BODY', '(call 1)'), imports)(), 4);