зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1246116: Wire BrTable in wasm and add a bunch of tests; r=sunfish
MozReview-Commit-ID: 7sw9zUD44OW
This commit is contained in:
Родитель
d95ecfa483
Коммит
577d0af387
|
@ -6500,9 +6500,7 @@ CheckSwitch(FunctionValidator& f, ParseNode* switchStmt)
|
|||
if (!f.encoder().writeExpr(Expr::BrTable))
|
||||
return false;
|
||||
|
||||
// Write default depth and number of cases (tableLength - 1 + 1 (default)).
|
||||
if (!f.encoder().writeVarU32(defaultDepth))
|
||||
return false;
|
||||
// Write the number of cases (tableLength - 1 + 1 (default)).
|
||||
if (!f.encoder().writeVarU32(tableLength))
|
||||
return false;
|
||||
|
||||
|
@ -6514,6 +6512,10 @@ CheckSwitch(FunctionValidator& f, ParseNode* switchStmt)
|
|||
return false;
|
||||
}
|
||||
|
||||
// Write the default depth.
|
||||
if (!f.encoder().writeVarU32(defaultDepth))
|
||||
return false;
|
||||
|
||||
// Subtract lowest case value, so that all the cases start from 0.
|
||||
if (low) {
|
||||
if (!f.encoder().writeExpr(Expr::I32Sub))
|
||||
|
|
|
@ -416,7 +416,7 @@ DecodeBr(FunctionDecoder& f, ExprType expected)
|
|||
{
|
||||
uint32_t relativeDepth;
|
||||
if (!f.d().readVarU32(&relativeDepth))
|
||||
return false;
|
||||
return f.fail("expected relative depth");
|
||||
|
||||
if (!f.isLabelInBounds(relativeDepth))
|
||||
return f.fail("branch depth exceeds current nesting level");
|
||||
|
@ -429,7 +429,7 @@ DecodeBrIf(FunctionDecoder& f, ExprType expected)
|
|||
{
|
||||
uint32_t relativeDepth;
|
||||
if (!f.d().readVarU32(&relativeDepth))
|
||||
return false;
|
||||
return f.fail("expected relative depth");
|
||||
|
||||
if (!f.isLabelInBounds(relativeDepth))
|
||||
return f.fail("branch depth exceeds current nesting level");
|
||||
|
@ -438,6 +438,32 @@ DecodeBrIf(FunctionDecoder& f, ExprType expected)
|
|||
DecodeExpr(f, ExprType::I32);
|
||||
}
|
||||
|
||||
static bool
|
||||
DecodeBrTable(FunctionDecoder& f)
|
||||
{
|
||||
uint32_t tableLength;
|
||||
if (!f.d().readVarU32(&tableLength))
|
||||
return false;
|
||||
if (tableLength > MaxBrTableElems)
|
||||
return f.fail("too many br_table entries");
|
||||
|
||||
for (uint32_t i = 0; i < tableLength; i++) {
|
||||
uint32_t depth;
|
||||
if (!f.d().readVarU32(&depth))
|
||||
return f.fail("missing br_table entry");
|
||||
if (!f.isLabelInBounds(depth))
|
||||
return f.fail("branch depth exceeds current nesting level");
|
||||
}
|
||||
|
||||
uint32_t defaultDepth;
|
||||
if (!f.d().readVarU32(&defaultDepth))
|
||||
return f.fail("expected default relative depth");
|
||||
if (!f.isLabelInBounds(defaultDepth))
|
||||
return f.fail("branch depth exceeds current nesting level");
|
||||
|
||||
return DecodeExpr(f, ExprType::I32);
|
||||
}
|
||||
|
||||
static bool
|
||||
DecodeReturn(FunctionDecoder& f)
|
||||
{
|
||||
|
@ -671,6 +697,8 @@ DecodeExpr(FunctionDecoder& f, ExprType expected)
|
|||
return DecodeBr(f, expected);
|
||||
case Expr::BrIf:
|
||||
return DecodeBrIf(f, expected);
|
||||
case Expr::BrTable:
|
||||
return DecodeBrTable(f);
|
||||
case Expr::Return:
|
||||
return DecodeReturn(f);
|
||||
default:
|
||||
|
|
|
@ -64,7 +64,7 @@ enum class Expr : uint16_t
|
|||
// Calls
|
||||
Call = 0x12,
|
||||
CallIndirect = 0x13,
|
||||
CallImport = 0x09,
|
||||
CallImport = 0x1f,
|
||||
|
||||
// Constants and calls
|
||||
I32Const = 0x0a,
|
||||
|
@ -827,6 +827,7 @@ static const unsigned MaxImports = 4 * 1024;
|
|||
static const unsigned MaxExports = 4 * 1024;
|
||||
static const unsigned MaxTableElems = 128 * 1024;
|
||||
static const unsigned MaxArgsPerFunc = 4 * 1024;
|
||||
static const unsigned MaxBrTableElems = 4 * 1024;
|
||||
|
||||
} // namespace wasm
|
||||
} // namespace js
|
||||
|
|
|
@ -2524,16 +2524,8 @@ EmitIfElse(FunctionCompiler& f, bool hasElse, ExprType expected, MDefinition** d
|
|||
static bool
|
||||
EmitBrTable(FunctionCompiler& f)
|
||||
{
|
||||
uint32_t defaultDepth = f.readVarU32();
|
||||
uint32_t numCases = f.readVarU32();
|
||||
|
||||
// Empty table
|
||||
if (!numCases) {
|
||||
MDefinition* _;
|
||||
return EmitExpr(f, ExprType::I32, &_) &&
|
||||
f.br(defaultDepth);
|
||||
}
|
||||
|
||||
BlockVector cases;
|
||||
if (!cases.resize(numCases))
|
||||
return false;
|
||||
|
@ -2545,10 +2537,16 @@ EmitBrTable(FunctionCompiler& f)
|
|||
for (size_t i = 0; i < numCases; i++)
|
||||
depths[i] = f.readVarU32();
|
||||
|
||||
uint32_t defaultDepth = f.readVarU32();
|
||||
|
||||
MDefinition* index;
|
||||
if (!EmitExpr(f, ExprType::I32, &index))
|
||||
return false;
|
||||
|
||||
// Empty table
|
||||
if (!numCases)
|
||||
return f.br(defaultDepth);
|
||||
|
||||
MBasicBlock* switchBlock;
|
||||
if (!f.startSwitch(index, numCases, &switchBlock))
|
||||
return false;
|
||||
|
|
|
@ -3154,10 +3154,9 @@ class Resolver
|
|||
return ref.name().empty() || resolveRef(varMap_, ref);
|
||||
}
|
||||
bool resolveTarget(WasmRef& ref) {
|
||||
for (size_t i = targetStack_.length(); i > 0; i--) {
|
||||
uint32_t targetIndex = i - 1;
|
||||
if (targetStack_[targetIndex] == ref.name()) {
|
||||
ref.setIndex(targetIndex);
|
||||
for (size_t i = 0, e = targetStack_.length(); i < e; i++) {
|
||||
if (targetStack_[e - i - 1] == ref.name()) {
|
||||
ref.setIndex(i);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -3659,9 +3658,6 @@ EncodeBranchTable(Encoder& e, WasmAstBranchTable& bt)
|
|||
if (!e.writeExpr(Expr::BrTable))
|
||||
return false;
|
||||
|
||||
if (!e.writeVarU32(bt.def().index()))
|
||||
return false;
|
||||
|
||||
if (!e.writeVarU32(bt.table().length()))
|
||||
return false;
|
||||
|
||||
|
@ -3670,6 +3666,9 @@ EncodeBranchTable(Encoder& e, WasmAstBranchTable& bt)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!e.writeVarU32(bt.def().index()))
|
||||
return false;
|
||||
|
||||
return EncodeExpr(e, bt.index());
|
||||
}
|
||||
|
||||
|
|
|
@ -147,33 +147,266 @@ assertThrowsInstanceOf(() => wasmEvalText('(module (func (return (i32.const 1)))
|
|||
// ----------------------------------------------------------------------------
|
||||
// br / br_if
|
||||
|
||||
wasmTextToBinary('(module (func (br 0)))');
|
||||
wasmTextToBinary('(module (func (block (br 0))))');
|
||||
wasmTextToBinary('(module (func (block $l (br $l))))');
|
||||
wasmTextToBinary('(module (func (br_if 0 (i32.const 0))))');
|
||||
wasmTextToBinary('(module (func (result i32) (block (br_if 0 (i32.const 1)))))');
|
||||
wasmTextToBinary('(module (func (result i32) (block $l (br_if $l (i32.const 1)))))');
|
||||
|
||||
wasmTextToBinary('(module (func (block $l (block $m (br $l)))))');
|
||||
wasmTextToBinary('(module (func (block $l (block $m (br $m)))))');
|
||||
|
||||
assertErrorMessage(() => wasmEvalText('(module (func (br 1)))'), TypeError, /branch depth exceeds current nesting level/);
|
||||
assertErrorMessage(() => wasmEvalText('(module (func (br_if 1 (i32.const 0))))'), TypeError, /branch depth exceeds current nesting level/);
|
||||
assertErrorMessage(() => wasmEvalText('(module (func (result i32) (block (br 0))) (export "" 0))'), TypeError, mismatchError("void", "i32"));
|
||||
assertErrorMessage(() => wasmEvalText('(module (func (result i32) (block (br_if 0 (i32.const 0)))) (export "" 0))'), TypeError, mismatchError("void", "i32"));
|
||||
|
||||
const DEPTH_OUT_OF_BOUNDS = /branch depth exceeds current nesting level/;
|
||||
|
||||
assertErrorMessage(() => wasmEvalText('(module (func (br 0)))'), TypeError, DEPTH_OUT_OF_BOUNDS);
|
||||
assertErrorMessage(() => wasmEvalText('(module (func (block (br 1))))'), TypeError, DEPTH_OUT_OF_BOUNDS);
|
||||
assertErrorMessage(() => wasmEvalText('(module (func (loop (br 2))))'), TypeError, DEPTH_OUT_OF_BOUNDS);
|
||||
|
||||
assertErrorMessage(() => wasmEvalText('(module (func (br_if 0 (i32.const 0))))'), TypeError, DEPTH_OUT_OF_BOUNDS);
|
||||
assertErrorMessage(() => wasmEvalText('(module (func (block (br_if 1 (i32.const 0)))))'), TypeError, DEPTH_OUT_OF_BOUNDS);
|
||||
assertErrorMessage(() => wasmEvalText('(module (func (loop (br_if 2 (i32.const 0)))))'), TypeError, DEPTH_OUT_OF_BOUNDS);
|
||||
|
||||
assertErrorMessage(() => wasmEvalText(`(module (func (result i32)
|
||||
(block
|
||||
(if_else
|
||||
(br 0)
|
||||
(i32.const 0)
|
||||
(i32.const 2)
|
||||
)
|
||||
)
|
||||
) (export "" 0))`), TypeError, mismatchError("void", "i32"));
|
||||
|
||||
assertErrorMessage(() => wasmEvalText(`(module (func (block $out (br_if $out (br 0)))) (export "" 0))`), TypeError, mismatchError("void", "i32"));
|
||||
|
||||
assertEq(wasmEvalText('(module (func (block (br 0))) (export "" 0))')(), undefined);
|
||||
assertEq(wasmEvalText('(module (func (block $l (br $l))) (export "" 0))')(), undefined);
|
||||
|
||||
assertEq(wasmEvalText('(module (func (block (block (br 1)))) (export "" 0))')(), undefined);
|
||||
assertEq(wasmEvalText('(module (func (block $l (block (br $l)))) (export "" 0))')(), undefined);
|
||||
|
||||
assertEq(wasmEvalText('(module (func (block $l (block $m (br $l)))) (export "" 0))')(), undefined);
|
||||
assertEq(wasmEvalText('(module (func (block $l (block $m (br $m)))) (export "" 0))')(), undefined);
|
||||
|
||||
assertEq(wasmEvalText(`(module (func (result i32)
|
||||
(block
|
||||
(br 0)
|
||||
(return (i32.const 0))
|
||||
)
|
||||
(return (i32.const 1))
|
||||
) (export "" 0))`)(), 1);
|
||||
|
||||
assertEq(wasmEvalText(`(module (func (result i32)
|
||||
(block
|
||||
(block
|
||||
(br 0)
|
||||
(return (i32.const 0))
|
||||
)
|
||||
(return (i32.const 1))
|
||||
)
|
||||
(return (i32.const 2))
|
||||
) (export "" 0))`)(), 1);
|
||||
|
||||
assertEq(wasmEvalText(`(module (func (result i32)
|
||||
(block $outer
|
||||
(block $inner
|
||||
(br $inner)
|
||||
(return (i32.const 0))
|
||||
)
|
||||
(return (i32.const 1))
|
||||
)
|
||||
(return (i32.const 2))
|
||||
) (export "" 0))`)(), 1);
|
||||
|
||||
// TODO enable once bug 1253572 is fixed.
|
||||
/*
|
||||
var notcalled = false;
|
||||
var called = false;
|
||||
var imports = {
|
||||
notcalled() {notcalled = true},
|
||||
called() {called = true}
|
||||
};
|
||||
assertEq(wasmEvalText(`(module (import "inc" "") (func
|
||||
(block
|
||||
(return (br 0))
|
||||
(call_import 0)
|
||||
)
|
||||
(call_import 1)
|
||||
) (export "" 0))`)(imports), undefined);
|
||||
assertEq(notcalled, false);
|
||||
assertEq(called, true);
|
||||
|
||||
assertEq(wasmEvalText(`(module (func
|
||||
(block
|
||||
(i32.add
|
||||
(i32.const 0)
|
||||
(return (br 0))
|
||||
)
|
||||
)
|
||||
(return)
|
||||
) (export "" 0))`)(), 1);
|
||||
*/
|
||||
|
||||
assertEq(wasmEvalText(`(module (func (result i32)
|
||||
(block
|
||||
(if_else
|
||||
(i32.const 1)
|
||||
(br 0)
|
||||
(return (i32.const 0))
|
||||
)
|
||||
)
|
||||
(return (i32.const 1))
|
||||
) (export "" 0))`)(), 1);
|
||||
|
||||
assertEq(wasmEvalText('(module (func (block (br_if 0 (i32.const 1)))) (export "" 0))')(), undefined);
|
||||
assertEq(wasmEvalText('(module (func (block (br_if 0 (i32.const 0)))) (export "" 0))')(), undefined);
|
||||
assertEq(wasmEvalText('(module (func (block $l (br_if $l (i32.const 1)))) (export "" 0))')(), undefined);
|
||||
|
||||
var isNonZero = wasmEvalText(`(module (func (result i32) (param i32)
|
||||
(block
|
||||
(br_if 0 (get_local 0))
|
||||
(return (i32.const 0))
|
||||
)
|
||||
(return (i32.const 1))
|
||||
) (export "" 0))`);
|
||||
|
||||
assertEq(isNonZero(0), 0);
|
||||
assertEq(isNonZero(1), 1);
|
||||
assertEq(isNonZero(-1), 1);
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// loop
|
||||
|
||||
wasmTextToBinary('(module (func (loop (br 0))))');
|
||||
wasmTextToBinary('(module (func (loop (br 1))))');
|
||||
wasmTextToBinary('(module (func (loop $a (br $a))))');
|
||||
wasmTextToBinary('(module (func (loop $a $b (br $a))))');
|
||||
wasmTextToBinary('(module (func (loop $a $b (br $b))))');
|
||||
wasmTextToBinary('(module (func (loop $a $a (br $a))))');
|
||||
assertErrorMessage(() => wasmEvalText('(module (func (loop (br 2))))'), TypeError, DEPTH_OUT_OF_BOUNDS);
|
||||
|
||||
assertEq(wasmEvalText('(module (func (loop)) (export "" 0))')(), undefined);
|
||||
assertEq(wasmEvalText('(module (func (result i32) (loop (i32.const 2)) (i32.const 1)) (export "" 0))')(), 1);
|
||||
|
||||
assertEq(wasmEvalText('(module (func (loop (br 1))) (export "" 0))')(), undefined);
|
||||
assertEq(wasmEvalText('(module (func (loop $a (br $a))) (export "" 0))')(), undefined);
|
||||
assertEq(wasmEvalText('(module (func (loop $a $b (br $a))) (export "" 0))')(), undefined);
|
||||
|
||||
assertEq(wasmEvalText(`(module (func (result i32) (local i32)
|
||||
(loop
|
||||
$break $continue
|
||||
(if
|
||||
(i32.gt_u (get_local 0) (i32.const 5))
|
||||
(br $break)
|
||||
)
|
||||
(set_local 0 (i32.add (get_local 0) (i32.const 1)))
|
||||
(br $continue)
|
||||
)
|
||||
(return (get_local 0))
|
||||
) (export "" 0))`)(), 6);
|
||||
|
||||
assertEq(wasmEvalText(`(module (func (result i32) (local i32)
|
||||
(loop
|
||||
$break $continue
|
||||
(br_if
|
||||
$break
|
||||
(i32.gt_u (get_local 0) (i32.const 5))
|
||||
)
|
||||
(set_local 0 (i32.add (get_local 0) (i32.const 1)))
|
||||
(br $continue)
|
||||
)
|
||||
(return (get_local 0))
|
||||
) (export "" 0))`)(), 6);
|
||||
|
||||
assertEq(wasmEvalText(`(module (func (result i32) (local i32)
|
||||
(loop
|
||||
$break $continue
|
||||
(set_local 0 (i32.add (get_local 0) (i32.const 1)))
|
||||
(br_if
|
||||
$continue
|
||||
(i32.le_u (get_local 0) (i32.const 5))
|
||||
)
|
||||
)
|
||||
(return (get_local 0))
|
||||
) (export "" 0))`)(), 6);
|
||||
|
||||
assertEq(wasmEvalText(`(module (func (result i32) (local i32)
|
||||
(loop
|
||||
$break $continue
|
||||
(br_if
|
||||
$break
|
||||
(i32.gt_u (get_local 0) (i32.const 5))
|
||||
)
|
||||
(set_local 0 (i32.add (get_local 0) (i32.const 1)))
|
||||
(loop
|
||||
(br $continue)
|
||||
)
|
||||
(return (i32.const 42))
|
||||
)
|
||||
(return (get_local 0))
|
||||
) (export "" 0))`)(), 6);
|
||||
|
||||
assertEq(wasmEvalText(`(module (func (result i32) (local i32)
|
||||
(loop
|
||||
$break $continue
|
||||
(set_local 0 (i32.add (get_local 0) (i32.const 1)))
|
||||
(loop
|
||||
(br_if
|
||||
$continue
|
||||
(i32.le_u (get_local 0) (i32.const 5))
|
||||
)
|
||||
)
|
||||
(br $break)
|
||||
)
|
||||
(return (get_local 0))
|
||||
) (export "" 0))`)(), 6);
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// tableswitch
|
||||
// br_table
|
||||
|
||||
assertErrorMessage(() => wasmEvalText('(module (func (br_table (i32.const 0) (table) (br 0))))'), TypeError, DEPTH_OUT_OF_BOUNDS);
|
||||
|
||||
assertErrorMessage(() => wasmEvalText('(module (func (block (br_table (i32.const 0) (table (br 2)) (br 0)))))'), TypeError, DEPTH_OUT_OF_BOUNDS);
|
||||
|
||||
assertErrorMessage(() => wasmEvalText('(module (func (block (br_table (f32.const 0) (table) (br 0)))))'), TypeError, mismatchError("f32", "i32"));
|
||||
|
||||
assertEq(wasmEvalText(`(module (func (result i32) (param i32)
|
||||
(block $default
|
||||
(br_table (get_local 0) (table) (br $default))
|
||||
(return (i32.const 0))
|
||||
)
|
||||
(return (i32.const 1))
|
||||
) (export "" 0))`)(), 1);
|
||||
|
||||
assertEq(wasmEvalText(`(module (func (result i32) (param i32)
|
||||
(block $default
|
||||
(br_table (return (i32.const 1)) (table) (br $default))
|
||||
(return (i32.const 0))
|
||||
)
|
||||
(return (i32.const 2))
|
||||
) (export "" 0))`)(), 1);
|
||||
|
||||
assertEq(wasmEvalText(`(module (func (result i32) (param i32)
|
||||
(block $outer
|
||||
(block $inner
|
||||
(br_table (get_local 0) (table) (br $inner))
|
||||
(return (i32.const 0))
|
||||
)
|
||||
(return (i32.const 1))
|
||||
)
|
||||
(return (i32.const 2))
|
||||
) (export "" 0))`)(), 1);
|
||||
|
||||
var f = wasmEvalText(`(module (func (result i32) (param i32)
|
||||
(block $0
|
||||
(block $1
|
||||
(block $2
|
||||
(block $default
|
||||
(br_table
|
||||
(get_local 0)
|
||||
(table (br $0) (br $1) (br $2))
|
||||
(br $default)
|
||||
)
|
||||
)
|
||||
(return (i32.const -1))
|
||||
)
|
||||
(return (i32.const 2))
|
||||
)
|
||||
)
|
||||
(return (i32.const 0))
|
||||
) (export "" 0))`);
|
||||
|
||||
assertEq(f(-2), -1);
|
||||
assertEq(f(-1), -1);
|
||||
assertEq(f(0), 0);
|
||||
assertEq(f(1), 0);
|
||||
assertEq(f(2), 2);
|
||||
assertEq(f(3), -1);
|
||||
|
||||
wasmTextToBinary('(module (func (param i32) (block $b1 (block $b2 (br_table (get_local 0) (table (br $b1) (br $b2)) (br $b2))))))');
|
||||
wasmTextToBinary('(module (func (param i32) (block $b1 (br_table (get_local 0) (table) (br $b1)))))');
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
// |jit-test| exitstatus: 6;
|
||||
load(libdir + "wasm.js");
|
||||
|
||||
setJitCompilerOption("signals.enable", 0);
|
||||
timeout(1);
|
||||
wasmEvalText('(module (func (loop (br 0))) (export "" 0))')();
|
||||
assertEq(true, false);
|
|
@ -0,0 +1,6 @@
|
|||
// |jit-test| exitstatus: 6;
|
||||
load(libdir + "wasm.js");
|
||||
|
||||
timeout(1);
|
||||
wasmEvalText('(module (func (loop (br 0))) (export "" 0))')();
|
||||
assertEq(true, false);
|
Загрузка…
Ссылка в новой задаче