Merge inbound to mozilla-central. a=merge

This commit is contained in:
shindli 2019-05-30 00:52:13 +03:00
Родитель 52385efdd3 5d02a20efb
Коммит ec43d5678c
12 изменённых файлов: 447 добавлений и 357 удалений

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

@ -84,8 +84,8 @@ for (let v of VALUES)
//
// - through WebAssembly.Table.prototype.set()
// - through the table.set, table.copy, and table.grow instructions
// - unimplemented: through table.fill
// - unimplemented: through WebAssembly.Table.prototype.grow()
// - through table.fill
// - through WebAssembly.Table.prototype.grow()
//
// Their values can be read in several ways:
//

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

@ -1,145 +1,145 @@
// |jit-test| skip-if: !wasmReftypesEnabled()
let ins
= wasmEvalText(
`(module
(table 8 anyref) ;; table 0
(table $t 10 anyref) ;; table 1
const N = 8;
;; fill/get for table 0, referenced implicitly
(func (export "fill0") (param $i i32) (param $r anyref) (param $n i32)
(table.fill (local.get $i) (local.get $r) (local.get $n))
)
(func (export "get0") (param $i i32) (result anyref)
(table.get (local.get $i))
)
function testTableFill(type, obj) {
assertEq(obj.length, N);
;; fill/get for table 1, referenced explicitly
(func (export "fill1") (param $i i32) (param $r anyref) (param $n i32)
(table.fill $t (local.get $i) (local.get $r) (local.get $n))
)
(func (export "get1") (param $i i32) (result anyref)
(table.get $t (local.get $i))
)
)`);
let ins
= wasmEvalText(
`(module
(table 8 ${type}) ;; table 0
(table $t 10 ${type}) ;; table 1
function Obj(n) {
this.n = n;
;; fill/get for table 0, referenced implicitly
(func (export "fill0") (param $i i32) (param $r ${type}) (param $n i32)
(table.fill (local.get $i) (local.get $r) (local.get $n))
)
(func (export "get0") (param $i i32) (result ${type})
(table.get (local.get $i))
)
;; fill/get for table 1, referenced explicitly
(func (export "fill1") (param $i i32) (param $r ${type}) (param $n i32)
(table.fill $t (local.get $i) (local.get $r) (local.get $n))
)
(func (export "get1") (param $i i32) (result ${type})
(table.get $t (local.get $i))
)
)`);
// An initial test to ascertain that tables 0 and 1 are independent
// Fill in table 0, then check it.
assertEq(ins.exports.fill0(2, obj[6], 5), undefined)
assertEq(ins.exports.fill0(1, obj[7], 3), undefined);
function check_table0() {
assertEq(ins.exports.get0(0), null);
assertEq(ins.exports.get0(1), obj[7]);
assertEq(ins.exports.get0(2), obj[7]);
assertEq(ins.exports.get0(3), obj[7]);
assertEq(ins.exports.get0(4), obj[6]);
assertEq(ins.exports.get0(5), obj[6]);
assertEq(ins.exports.get0(6), obj[6]);
assertEq(ins.exports.get0(7), null);
}
// Check that table 0 has the expected content.
check_table0();
// Check that messing with table 0 above hasn't changed table 1.
for (let i = 0; i < 10; i++) {
assertEq(ins.exports.get1(i), null);
}
// Now a bunch of tests involving only table 1.
// Within the table
assertEq(ins.exports.fill1(2, obj[0], 3), undefined);
assertEq(ins.exports.get1(1), null);
assertEq(ins.exports.get1(2), obj[0]);
assertEq(ins.exports.get1(3), obj[0]);
assertEq(ins.exports.get1(4), obj[0]);
assertEq(ins.exports.get1(5), null);
// Within the table
assertEq(ins.exports.fill1(4, obj[1], 2), undefined);
assertEq(ins.exports.get1(3), obj[0]);
assertEq(ins.exports.get1(4), obj[1]);
assertEq(ins.exports.get1(5), obj[1]);
assertEq(ins.exports.get1(6), null);
// Within the table
assertEq(ins.exports.fill1(4, obj[2], 0), undefined);
assertEq(ins.exports.get1(3), obj[0]);
assertEq(ins.exports.get1(4), obj[1]);
assertEq(ins.exports.get1(5), obj[1]);
// Within the table
assertEq(ins.exports.fill1(8, obj[3], 2), undefined);
assertEq(ins.exports.get1(7), null);
assertEq(ins.exports.get1(8), obj[3]);
assertEq(ins.exports.get1(9), obj[3]);
// Within the table
assertEq(ins.exports.fill1(9, null, 1), undefined);
assertEq(ins.exports.get1(8), obj[3]);
assertEq(ins.exports.get1(9), null);
// Within the table
assertEq(ins.exports.fill1(10, obj[4], 0), undefined);
assertEq(ins.exports.get1(9), null);
// Partly outside the table
assertErrorMessage(() => ins.exports.fill1(8, obj[5], 3),
RangeError, /table index out of bounds/);
assertEq(ins.exports.get1(7), null);
assertEq(ins.exports.get1(8), obj[5]);
assertEq(ins.exports.get1(9), obj[5]);
// Boundary tests on table 1: at the edge of the table.
// Length-zero fill1 at the edge of the table must succeed
assertEq(ins.exports.fill1(10, null, 0), undefined);
// Length-one fill1 at the edge of the table fails
assertErrorMessage(() => ins.exports.fill1(10, null, 1),
RangeError, /table index out of bounds/);
// Length-more-than-one fill1 at the edge of the table fails
assertErrorMessage(() => ins.exports.fill1(10, null, 2),
RangeError, /table index out of bounds/);
// Boundary tests on table 1: beyond the edge of the table:
// Length-zero fill1 beyond the edge of the table fails
assertErrorMessage(() => ins.exports.fill1(11, null, 0),
RangeError, /table index out of bounds/);
// Length-one fill1 beyond the edge of the table fails
assertErrorMessage(() => ins.exports.fill1(11, null, 1),
RangeError, /table index out of bounds/);
// Length-more-than-one fill1 beyond the edge of the table fails
assertErrorMessage(() => ins.exports.fill1(11, null, 2),
RangeError, /table index out of bounds/);
// Following all the above tests on table 1, check table 0 hasn't changed.
check_table0();
}
function mkObj(n) {
return new Obj(n);
}
var objs = [];
for (var i = 0; i < N; i++)
objs[i] = {n:i};
testTableFill('anyref', objs);
const obj1 = mkObj(1);
const obj2 = mkObj(2);
const obj3 = mkObj(3);
const obj4 = mkObj(4);
const obj5 = mkObj(5);
const obj6 = mkObj(6);
const obj7 = mkObj(7);
const obj8 = mkObj(8);
// An initial test to ascertain that tables 0 and 1 are independent
// Fill in table 0, then check it.
assertEq(ins.exports.fill0(2, obj7, 5), undefined)
assertEq(ins.exports.fill0(1, obj8, 3), undefined);
function check_table0() {
assertEq(ins.exports.get0(0), null);
assertEq(ins.exports.get0(1), obj8);
assertEq(ins.exports.get0(2), obj8);
assertEq(ins.exports.get0(3), obj8);
assertEq(ins.exports.get0(4), obj7);
assertEq(ins.exports.get0(5), obj7);
assertEq(ins.exports.get0(6), obj7);
assertEq(ins.exports.get0(7), null);
}
// Check that table 0 has the expected content.
check_table0();
// Check that messing with table 0 above hasn't changed table 1.
for (let i = 0; i < 10; i++) {
assertEq(ins.exports.get1(i), null);
}
// Now a bunch of tests involving only table 1.
// Within the table
assertEq(ins.exports.fill1(2, obj1, 3), undefined);
assertEq(ins.exports.get1(1), null);
assertEq(ins.exports.get1(2), obj1);
assertEq(ins.exports.get1(3), obj1);
assertEq(ins.exports.get1(4), obj1);
assertEq(ins.exports.get1(5), null);
// Within the table
assertEq(ins.exports.fill1(4, obj2, 2), undefined);
assertEq(ins.exports.get1(3), obj1);
assertEq(ins.exports.get1(4), obj2);
assertEq(ins.exports.get1(5), obj2);
assertEq(ins.exports.get1(6), null);
// Within the table
assertEq(ins.exports.fill1(4, obj3, 0), undefined);
assertEq(ins.exports.get1(3), obj1);
assertEq(ins.exports.get1(4), obj2);
assertEq(ins.exports.get1(5), obj2);
// Within the table
assertEq(ins.exports.fill1(8, obj4, 2), undefined);
assertEq(ins.exports.get1(7), null);
assertEq(ins.exports.get1(8), obj4);
assertEq(ins.exports.get1(9), obj4);
// Within the table
assertEq(ins.exports.fill1(9, null, 1), undefined);
assertEq(ins.exports.get1(8), obj4);
assertEq(ins.exports.get1(9), null);
// Within the table
assertEq(ins.exports.fill1(10, obj5, 0), undefined);
assertEq(ins.exports.get1(9), null);
// Partly outside the table
assertErrorMessage(() => ins.exports.fill1(8, obj6, 3),
RangeError, /table index out of bounds/);
assertEq(ins.exports.get1(7), null);
assertEq(ins.exports.get1(8), obj6);
assertEq(ins.exports.get1(9), obj6);
// Boundary tests on table 1: at the edge of the table.
// Length-zero fill1 at the edge of the table must succeed
assertEq(ins.exports.fill1(10, null, 0), undefined);
// Length-one fill1 at the edge of the table fails
assertErrorMessage(() => ins.exports.fill1(10, null, 1),
RangeError, /table index out of bounds/);
// Length-more-than-one fill1 at the edge of the table fails
assertErrorMessage(() => ins.exports.fill1(10, null, 2),
RangeError, /table index out of bounds/);
// Boundary tests on table 1: beyond the edge of the table:
// Length-zero fill1 beyond the edge of the table fails
assertErrorMessage(() => ins.exports.fill1(11, null, 0),
RangeError, /table index out of bounds/);
// Length-one fill1 beyond the edge of the table fails
assertErrorMessage(() => ins.exports.fill1(11, null, 1),
RangeError, /table index out of bounds/);
// Length-more-than-one fill1 beyond the edge of the table fails
assertErrorMessage(() => ins.exports.fill1(11, null, 2),
RangeError, /table index out of bounds/);
var funcs = [];
for (var i = 0; i < N; i++)
funcs[i] = wasmEvalText(`(module (func (export "x") (result i32) (i32.const ${i})))`).exports.x;
testTableFill('funcref', funcs);
// Type errors. Required sig is: (i32, anyref, i32) -> void
@ -203,24 +203,3 @@ assertErrorMessage(() => wasmEvalText(
))`),
WebAssembly.CompileError,
/popping value from empty stack/);
assertErrorMessage(() => wasmEvalText(
`(module
(table $t 0 funcref)
(func $tables-of-funcref-not-allowed (param $r anyref)
(table.fill $t (i32.const 1) (local.get $r) (i32.const 1))
))`),
WebAssembly.CompileError, /table.fill only on tables of anyref/);
assertErrorMessage(() => wasmEvalText(
`(module
(table $t1 1 anyref)
(table $t2 1 funcref)
(func $tables-of-funcref-not-allowed-2 (param $r anyref)
(table.fill $t2 (i32.const 0) (local.get $r) (i32.const 1))
))`),
WebAssembly.CompileError, /table.fill only on tables of anyref/);
// Following all the above tests on table 1, check table 0 hasn't changed.
check_table0();

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

@ -154,22 +154,25 @@ function dummy() { return 37 }
//
// table.get and table.set
const wasmFun = wasmEvalText(`(module (func (export "x")))`).exports.x;
// table.get in bounds - returns right value type & value
// table.get out of bounds - fails
{
function testTableGet(type, x) {
let ins = wasmEvalText(
`(module
(table (export "t") 10 anyref)
(func (export "f") (param i32) (result anyref)
(table (export "t") 10 ${type})
(func (export "f") (param i32) (result ${type})
(table.get (local.get 0))))`);
let x = {};
ins.exports.t.set(0, x);
assertEq(ins.exports.f(0), x);
assertEq(ins.exports.f(1), null);
assertErrorMessage(() => ins.exports.f(10), RangeError, /index out of bounds/);
assertErrorMessage(() => ins.exports.f(-5), RangeError, /index out of bounds/);
}
testTableGet('anyref', {});
testTableGet('funcref', wasmFun);
// table.get with non-i32 index - fails validation
@ -181,25 +184,6 @@ assertErrorMessage(() => new WebAssembly.Module(wasmTextToBinary(
WebAssembly.CompileError,
/type mismatch/);
// table.get on table of funcref - fails validation because funcref is not expressible
// Both with and without anyref support
assertErrorMessage(() => new WebAssembly.Module(wasmTextToBinary(
`(module
(table 10 funcref)
(func (export "f") (param i32)
(drop (table.get (local.get 0)))))`)),
WebAssembly.CompileError,
/table.get only on tables of anyref/);
assertErrorMessage(() => new WebAssembly.Module(wasmTextToBinary(
`(module
(table 10 funcref)
(func (export "f") (param i32)
(drop (table.get (local.get 0)))))`)),
WebAssembly.CompileError,
/table.get only on tables of anyref/);
// table.get when there are no tables - fails validation
assertErrorMessage(() => new WebAssembly.Module(wasmTextToBinary(
@ -213,15 +197,14 @@ assertErrorMessage(() => new WebAssembly.Module(wasmTextToBinary(
// table.set with null - works
// table.set out of bounds - fails
{
function testTableSet(type, x) {
let ins = wasmEvalText(
`(module
(table (export "t") 10 anyref)
(func (export "set_anyref") (param i32) (param anyref)
(table (export "t") 10 ${type})
(func (export "set_anyref") (param i32) (param ${type})
(table.set (local.get 0) (local.get 1)))
(func (export "set_null") (param i32)
(table.set (local.get 0) (ref.null))))`);
let x = {};
ins.exports.set_anyref(3, x);
assertEq(ins.exports.t.get(3), x);
ins.exports.set_null(3);
@ -230,6 +213,8 @@ assertErrorMessage(() => new WebAssembly.Module(wasmTextToBinary(
assertErrorMessage(() => ins.exports.set_anyref(10, x), RangeError, /index out of bounds/);
assertErrorMessage(() => ins.exports.set_anyref(-1, x), RangeError, /index out of bounds/);
}
testTableSet('anyref', {});
testTableSet('funcref', wasmFun);
// table.set with non-i32 index - fails validation
@ -241,7 +226,7 @@ assertErrorMessage(() => new WebAssembly.Module(wasmTextToBinary(
WebAssembly.CompileError,
/type mismatch/);
// table.set with non-anyref value - fails validation
// table.set with non-ref value - fails validation
assertErrorMessage(() => new WebAssembly.Module(wasmTextToBinary(
`(module
@ -250,16 +235,13 @@ assertErrorMessage(() => new WebAssembly.Module(wasmTextToBinary(
(table.set (i32.const 0) (local.get 0))))`)),
WebAssembly.CompileError,
/type mismatch/);
// table.set on table of funcref - fails validation
assertErrorMessage(() => new WebAssembly.Module(wasmTextToBinary(
`(module
(table 10 funcref)
(func (export "f") (param anyref)
(table.set (i32.const 0) (local.get 0))))`)),
(table 10 funcref)
(func (export "f") (param f64)
(table.set (i32.const 0) (local.get 0))))`)),
WebAssembly.CompileError,
/table.set only on tables of anyref/);
/type mismatch/);
// table.set when there are no tables - fails validation
@ -270,36 +252,43 @@ assertErrorMessage(() => new WebAssembly.Module(wasmTextToBinary(
WebAssembly.CompileError,
/table index out of range for table.set/);
// we can grow table of anyref
// table.grow with zero delta - always works even at maximum
// table.grow with delta - works and returns correct old value
// table.grow with delta at upper limit - fails
// table.grow with negative delta - fails
function testTableGrow(type, x) {
let ins = wasmEvalText(
`(module
(table (export "t") 10 20 ${type})
(func (export "grow") (param i32) (result i32)
(table.grow (ref.null) (local.get 0)))
(func (export "grow2") (param i32) (param ${type}) (result i32)
(table.grow (local.get 1) (local.get 0))))`);
let ins = wasmEvalText(
`(module
(table (export "t") 10 20 anyref)
(func (export "grow") (param i32) (result i32)
(table.grow (ref.null) (local.get 0))))`);
assertEq(ins.exports.grow(0), 10);
assertEq(ins.exports.t.length, 10);
assertEq(ins.exports.grow(1), 10);
assertEq(ins.exports.t.length, 11);
assertEq(ins.exports.t.get(10), null);
assertEq(ins.exports.grow(9), 11);
assertEq(ins.exports.t.length, 20);
assertEq(ins.exports.t.get(19), null);
assertEq(ins.exports.grow(0), 20);
// we can grow table of references
// table.grow with zero delta - always works even at maximum
// table.grow with delta - works and returns correct old value
// table.grow with delta at upper limit - fails
// table.grow with negative delta - fails
assertEq(ins.exports.grow(0), 10);
assertEq(ins.exports.t.length, 10);
assertEq(ins.exports.grow(1), 10);
assertEq(ins.exports.t.length, 11);
assertEq(ins.exports.t.get(10), null);
assertEq(ins.exports.grow2(9, x), 11);
assertEq(ins.exports.t.length, 20);
for (var i = 11; i < 20; i++)
assertEq(ins.exports.t.get(i), x);
assertEq(ins.exports.grow(0), 20);
// The JS API throws if it can't grow
assertErrorMessage(() => ins.exports.t.grow(1), RangeError, /failed to grow table/);
assertErrorMessage(() => ins.exports.t.grow(-1), TypeError, /bad [Tt]able grow delta/);
// The JS API throws if it can't grow
assertErrorMessage(() => ins.exports.t.grow(1), RangeError, /failed to grow table/);
assertErrorMessage(() => ins.exports.t.grow(-1), TypeError, /bad [Tt]able grow delta/);
// The wasm API does not throw if it can't grow, but returns -1
assertEq(ins.exports.grow(1), -1);
assertEq(ins.exports.t.length, 20);
assertEq(ins.exports.grow(-1), -1);
assertEq(ins.exports.t.length, 20)
// The wasm API does not throw if it can't grow, but returns -1
assertEq(ins.exports.grow(1), -1);
assertEq(ins.exports.t.length, 20);
assertEq(ins.exports.grow(-1), -1);
assertEq(ins.exports.t.length, 20)
}
testTableGrow('anyref', 42);
testTableGrow('funcref', wasmFun);
// Special case for private tables without a maximum
@ -315,16 +304,6 @@ assertEq(ins.exports.t.length, 20)
assertEq(ins.exports.grow(0), 20);
}
// Can't grow table of funcref yet
assertErrorMessage(() => wasmEvalText(
`(module
(table $t 2 funcref)
(func $f
(drop (table.grow (ref.null) (i32.const 1)))))`),
WebAssembly.CompileError,
/table.grow only on tables of anyref/);
// table.grow with non-i32 argument - fails validation
assertErrorMessage(() => new WebAssembly.Module(wasmTextToBinary(

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

@ -886,8 +886,8 @@ void Instance::initElems(uint32_t tableIndex, const ElemSegment& seg,
uint32_t tableIndex) {
MOZ_ASSERT(SASigTableFill.failureMode == FailureMode::FailOnNegI32);
JSContext* cx = TlsContext.get();
Table& table = *instance->tables()[tableIndex];
MOZ_RELEASE_ASSERT(table.kind() == TableKind::AnyRef);
if (len == 0) {
// Even though the length is zero, we must check for a valid offset. But
@ -912,10 +912,17 @@ void Instance::initElems(uint32_t tableIndex, const ElemSegment& seg,
mustTrap = true;
}
for (uint32_t i = 0; i < len; i++) {
uint32_t index = start + i;
MOZ_ASSERT(index < table.length());
table.setAnyRef(index, AnyRef::fromCompiledCode(value));
AnyRef ref = AnyRef::fromCompiledCode(value);
switch (table.kind()) {
case TableKind::AnyRef:
table.fillAnyRef(start, len, ref);
break;
case TableKind::FuncRef:
table.fillFuncRef(start, len, ref, cx);
break;
case TableKind::AsmJS:
MOZ_CRASH("not asm.js");
}
if (!mustTrap) {
@ -923,7 +930,6 @@ void Instance::initElems(uint32_t tableIndex, const ElemSegment& seg,
}
}
JSContext* cx = TlsContext.get();
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_WASM_TABLE_OUT_OF_BOUNDS);
return -1;
@ -932,30 +938,52 @@ void Instance::initElems(uint32_t tableIndex, const ElemSegment& seg,
/* static */ void* Instance::tableGet(Instance* instance, uint32_t index,
uint32_t tableIndex) {
MOZ_ASSERT(SASigTableGet.failureMode == FailureMode::FailOnInvalidRef);
const Table& table = *instance->tables()[tableIndex];
MOZ_RELEASE_ASSERT(table.kind() == TableKind::AnyRef);
if (index >= table.length()) {
JS_ReportErrorNumberASCII(TlsContext.get(), GetErrorMessage, nullptr,
JSMSG_WASM_TABLE_OUT_OF_BOUNDS);
return AnyRef::invalid().forCompiledCode();
}
return table.getAnyRef(index).forCompiledCode();
if (table.kind() == TableKind::AnyRef) {
return table.getAnyRef(index).forCompiledCode();
}
MOZ_RELEASE_ASSERT(table.kind() == TableKind::FuncRef);
JSContext* cx = TlsContext.get();
RootedFunction fun(cx);
if (!table.getFuncRef(cx, index, &fun)) {
return AnyRef::invalid().forCompiledCode();
}
return AnyRef::fromJSObject(fun).forCompiledCode();
}
/* static */ uint32_t Instance::tableGrow(Instance* instance, void* initValue,
uint32_t delta, uint32_t tableIndex) {
MOZ_ASSERT(SASigTableGrow.failureMode == FailureMode::Infallible);
RootedAnyRef obj(TlsContext.get(), AnyRef::fromCompiledCode(initValue));
RootedAnyRef ref(TlsContext.get(), AnyRef::fromCompiledCode(initValue));
Table& table = *instance->tables()[tableIndex];
MOZ_RELEASE_ASSERT(table.kind() == TableKind::AnyRef);
uint32_t oldSize = table.grow(delta, TlsContext.get());
JSContext* cx = TlsContext.get();
uint32_t oldSize = table.grow(delta, cx);
if (oldSize != uint32_t(-1) && initValue != nullptr) {
for (uint32_t i = 0; i < delta; i++) {
table.setAnyRef(oldSize + i, obj.get());
switch (table.kind()) {
case TableKind::AnyRef:
table.fillAnyRef(oldSize, delta, ref);
break;
case TableKind::FuncRef:
table.fillFuncRef(oldSize, delta, ref, cx);
break;
case TableKind::AsmJS:
MOZ_CRASH("not asm.js");
}
}
return oldSize;
}
@ -964,13 +992,25 @@ void Instance::initElems(uint32_t tableIndex, const ElemSegment& seg,
MOZ_ASSERT(SASigTableSet.failureMode == FailureMode::FailOnNegI32);
Table& table = *instance->tables()[tableIndex];
MOZ_RELEASE_ASSERT(table.kind() == TableKind::AnyRef);
if (index >= table.length()) {
JS_ReportErrorNumberASCII(TlsContext.get(), GetErrorMessage, nullptr,
JSMSG_WASM_TABLE_OUT_OF_BOUNDS);
return -1;
}
table.setAnyRef(index, AnyRef::fromCompiledCode(value));
AnyRef ref = AnyRef::fromCompiledCode(value);
switch (table.kind()) {
case TableKind::AnyRef:
table.fillAnyRef(index, 1, ref);
break;
case TableKind::FuncRef:
table.fillFuncRef(index, 1, ref, TlsContext.get());
break;
case TableKind::AsmJS:
MOZ_CRASH("not asm.js");
}
return 0;
}

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

@ -2128,23 +2128,11 @@ bool WasmTableObject::getImpl(JSContext* cx, const CallArgs& args) {
switch (table.kind()) {
case TableKind::FuncRef: {
const FunctionTableElem& elem = table.getFuncRef(index);
if (!elem.code) {
args.rval().setNull();
return true;
}
Instance& instance = *elem.tls->instance;
const CodeRange& codeRange = *instance.code().lookupFuncRange(elem.code);
RootedWasmInstanceObject instanceObj(cx, instance.object());
RootedFunction fun(cx);
if (!instanceObj->getExportedFunction(cx, instanceObj,
codeRange.funcIndex(), &fun)) {
if (!table.getFuncRef(cx, index, &fun)) {
return false;
}
args.rval().setObject(*fun);
args.rval().setObjectOrNull(fun);
break;
}
case TableKind::AnyRef: {
@ -2164,36 +2152,6 @@ bool WasmTableObject::get(JSContext* cx, unsigned argc, Value* vp) {
return CallNonGenericMethod<IsTable, getImpl>(cx, args);
}
static void TableFunctionFill(JSContext* cx, Table* table, HandleFunction value,
uint32_t index, uint32_t limit) {
if (!value) {
while (index < limit) {
table->setNull(index++);
}
return;
}
RootedWasmInstanceObject instanceObj(cx,
ExportedFunctionToInstanceObject(value));
uint32_t funcIndex = ExportedFunctionToFuncIndex(value);
#ifdef DEBUG
RootedFunction f(cx);
MOZ_ASSERT(instanceObj->getExportedFunction(cx, instanceObj, funcIndex, &f));
MOZ_ASSERT(value == f);
#endif
Instance& instance = instanceObj->instance();
Tier tier = instance.code().bestTier();
const MetadataTier& metadata = instance.metadata(tier);
const CodeRange& codeRange =
metadata.codeRange(metadata.lookupFuncExport(funcIndex));
void* code = instance.codeBase(tier) + codeRange.funcTableEntry();
while (index < limit) {
table->setFuncRef(index++, code, &instance);
}
}
/* static */
bool WasmTableObject::setImpl(JSContext* cx, const CallArgs& args) {
RootedWasmTableObject tableObj(
@ -2218,7 +2176,7 @@ bool WasmTableObject::setImpl(JSContext* cx, const CallArgs& args) {
}
MOZ_ASSERT(index < MaxTableLength);
static_assert(MaxTableLength < UINT32_MAX, "Invariant");
TableFunctionFill(cx, &table, fun, index, index + 1);
table.fillFuncRef(index, 1, AnyRef::fromJSObject(fun), cx);
break;
}
case TableKind::AnyRef: {
@ -2226,7 +2184,7 @@ bool WasmTableObject::setImpl(JSContext* cx, const CallArgs& args) {
if (!BoxAnyRef(cx, fillValue, &tmp)) {
return false;
}
table.setAnyRef(index, tmp);
table.fillAnyRef(index, 1, tmp);
break;
}
default: {
@ -2246,8 +2204,9 @@ bool WasmTableObject::set(JSContext* cx, unsigned argc, Value* vp) {
/* static */
bool WasmTableObject::growImpl(JSContext* cx, const CallArgs& args) {
RootedWasmTableObject table(cx,
&args.thisv().toObject().as<WasmTableObject>());
RootedWasmTableObject tableObj(
cx, &args.thisv().toObject().as<WasmTableObject>());
Table& table = tableObj->table();
if (!args.requireAtLeast(cx, "WebAssembly.Table.grow", 1)) {
return false;
@ -2258,7 +2217,7 @@ bool WasmTableObject::growImpl(JSContext* cx, const CallArgs& args) {
return false;
}
uint32_t oldLength = table->table().grow(delta, cx);
uint32_t oldLength = table.grow(delta, cx);
if (oldLength == uint32_t(-1)) {
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_GROW,
@ -2277,12 +2236,12 @@ bool WasmTableObject::growImpl(JSContext* cx, const CallArgs& args) {
static_assert(MaxTableLength < UINT32_MAX, "Invariant");
switch (table->table().kind()) {
switch (table.kind()) {
case TableKind::FuncRef: {
if (fillValue.isNull()) {
#ifdef DEBUG
for (uint32_t index = oldLength; index < oldLength + delta; index++) {
MOZ_ASSERT(table->table().getFuncRef(index).code == nullptr);
MOZ_ASSERT(table.getFuncRef(index).code == nullptr);
}
#endif
} else {
@ -2290,8 +2249,7 @@ bool WasmTableObject::growImpl(JSContext* cx, const CallArgs& args) {
if (!CheckFuncRefValue(cx, fillValue, &fun)) {
return false;
}
TableFunctionFill(cx, &table->table(), fun, oldLength,
oldLength + delta);
table.fillFuncRef(oldLength, delta, AnyRef::fromJSObject(fun), cx);
}
break;
}
@ -2301,13 +2259,11 @@ bool WasmTableObject::growImpl(JSContext* cx, const CallArgs& args) {
return false;
}
if (!tmp.get().isNull()) {
for (uint32_t index = oldLength; index < oldLength + delta; index++) {
table->table().setAnyRef(index, tmp);
}
table.fillAnyRef(oldLength, delta, tmp);
} else {
#ifdef DEBUG
for (uint32_t index = oldLength; index < oldLength + delta; index++) {
MOZ_ASSERT(table->table().getAnyRef(index).isNull());
MOZ_ASSERT(table.getAnyRef(index).isNull());
}
#endif
}

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

@ -1966,28 +1966,21 @@ inline bool OpIter<Policy>::readTableFill(uint32_t* tableIndex, Value* start,
Value* val, Value* len) {
MOZ_ASSERT(Classify(op_) == OpKind::TableFill);
if (!popWithType(ValType::I32, len)) {
return false;
}
if (!popWithType(ValType::AnyRef, val)) {
return false;
}
if (!popWithType(ValType::I32, start)) {
return false;
}
if (!readVarU32(tableIndex)) {
return false;
}
if (*tableIndex >= env_.tables.length()) {
return fail("table index out of range for table.fill");
}
if (env_.tables[*tableIndex].kind != TableKind::AnyRef) {
return fail("table.fill only on tables of anyref");
if (!popWithType(ValType::I32, len)) {
return false;
}
if (!popWithType(ToElemValType(env_.tables[*tableIndex].kind), val)) {
return false;
}
if (!popWithType(ValType::I32, start)) {
return false;
}
return true;
@ -1997,23 +1990,18 @@ template <typename Policy>
inline bool OpIter<Policy>::readTableGet(uint32_t* tableIndex, Value* index) {
MOZ_ASSERT(Classify(op_) == OpKind::TableGet);
if (!popWithType(ValType::I32, index)) {
return false;
}
if (!readVarU32(tableIndex)) {
return false;
}
if (*tableIndex >= env_.tables.length()) {
return fail("table index out of range for table.get");
}
if (env_.tables[*tableIndex].kind != TableKind::AnyRef) {
return fail("table.get only on tables of anyref");
if (!popWithType(ValType::I32, index)) {
return false;
}
infalliblePush(ValType::AnyRef);
infalliblePush(ToElemValType(env_.tables[*tableIndex].kind));
return true;
}
@ -2022,21 +2010,18 @@ inline bool OpIter<Policy>::readTableGrow(uint32_t* tableIndex,
Value* initValue, Value* delta) {
MOZ_ASSERT(Classify(op_) == OpKind::TableGrow);
if (!popWithType(ValType::I32, delta)) {
return false;
}
if (!popWithType(ValType::AnyRef, initValue)) {
return false;
}
if (!readVarU32(tableIndex)) {
return false;
}
if (*tableIndex >= env_.tables.length()) {
return fail("table index out of range for table.grow");
}
if (env_.tables[*tableIndex].kind != TableKind::AnyRef) {
return fail("table.grow only on tables of anyref");
if (!popWithType(ValType::I32, delta)) {
return false;
}
if (!popWithType(ToElemValType(env_.tables[*tableIndex].kind), initValue)) {
return false;
}
infalliblePush(ValType::I32);
@ -2048,21 +2033,18 @@ inline bool OpIter<Policy>::readTableSet(uint32_t* tableIndex, Value* index,
Value* value) {
MOZ_ASSERT(Classify(op_) == OpKind::TableSet);
if (!popWithType(ValType::AnyRef, value)) {
return false;
}
if (!popWithType(ValType::I32, index)) {
return false;
}
if (!readVarU32(tableIndex)) {
return false;
}
if (*tableIndex >= env_.tables.length()) {
return fail("table index out of range for table.set");
}
if (env_.tables[*tableIndex].kind != TableKind::AnyRef) {
return fail("table.set only on tables of anyref");
if (!popWithType(ToElemValType(env_.tables[*tableIndex].kind), value)) {
return false;
}
if (!popWithType(ValType::I32, index)) {
return false;
}
return true;

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

@ -139,12 +139,22 @@ const FunctionTableElem& Table::getFuncRef(uint32_t index) const {
return functions_[index];
}
AnyRef Table::getAnyRef(uint32_t index) const {
MOZ_ASSERT(!isFunction());
// TODO/AnyRef-boxing: With boxed immediates and strings, the write barrier
// is going to have to be more complicated.
ASSERT_ANYREF_IS_JSOBJECT;
return AnyRef::fromJSObject(objects_[index]);
bool Table::getFuncRef(JSContext* cx, uint32_t index,
MutableHandleFunction fun) const {
MOZ_ASSERT(isFunction());
const FunctionTableElem& elem = getFuncRef(index);
if (!elem.code) {
fun.set(nullptr);
return true;
}
Instance& instance = *elem.tls->instance;
const CodeRange& codeRange = *instance.code().lookupFuncRange(elem.code);
RootedWasmInstanceObject instanceObj(cx, instance.object());
return instanceObj->getExportedFunction(cx, instanceObj,
codeRange.funcIndex(), fun);
}
void Table::setFuncRef(uint32_t index, void* code, const Instance* instance) {
@ -171,12 +181,57 @@ void Table::setFuncRef(uint32_t index, void* code, const Instance* instance) {
}
}
void Table::setAnyRef(uint32_t index, AnyRef new_obj) {
void Table::fillFuncRef(uint32_t index, uint32_t fillCount, AnyRef ref,
JSContext* cx) {
MOZ_ASSERT(isFunction());
if (ref.isNull()) {
for (uint32_t i = index, end = index + fillCount; i != end; i++) {
setNull(i);
}
return;
}
RootedFunction fun(cx, &ref.asJSObject()->as<JSFunction>());
MOZ_RELEASE_ASSERT(IsWasmExportedFunction(fun));
RootedWasmInstanceObject instanceObj(cx,
ExportedFunctionToInstanceObject(fun));
uint32_t funcIndex = ExportedFunctionToFuncIndex(fun);
#ifdef DEBUG
RootedFunction f(cx);
MOZ_ASSERT(instanceObj->getExportedFunction(cx, instanceObj, funcIndex, &f));
MOZ_ASSERT(fun == f);
#endif
Instance& instance = instanceObj->instance();
Tier tier = instance.code().bestTier();
const MetadataTier& metadata = instance.metadata(tier);
const CodeRange& codeRange =
metadata.codeRange(metadata.lookupFuncExport(funcIndex));
void* code = instance.codeBase(tier) + codeRange.funcTableEntry();
for (uint32_t i = index, end = index + fillCount; i != end; i++) {
setFuncRef(i, code, &instance);
}
}
AnyRef Table::getAnyRef(uint32_t index) const {
MOZ_ASSERT(!isFunction());
// TODO/AnyRef-boxing: With boxed immediates and strings, the write barrier
// is going to have to be more complicated.
ASSERT_ANYREF_IS_JSOBJECT;
objects_[index] = new_obj.asJSObject();
return AnyRef::fromJSObject(objects_[index]);
}
void Table::fillAnyRef(uint32_t index, uint32_t fillCount, AnyRef ref) {
MOZ_ASSERT(!isFunction());
// TODO/AnyRef-boxing: With boxed immediates and strings, the write barrier
// is going to have to be more complicated.
ASSERT_ANYREF_IS_JSOBJECT;
for (uint32_t i = index, end = index + fillCount; i != end; i++) {
objects_[i] = ref.asJSObject();
}
}
void Table::setNull(uint32_t index) {
@ -192,7 +247,7 @@ void Table::setNull(uint32_t index) {
break;
}
case TableKind::AnyRef: {
setAnyRef(index, AnyRef::null());
fillAnyRef(index, 1, AnyRef::null());
break;
}
case TableKind::AsmJS: {
@ -223,7 +278,7 @@ void Table::copy(const Table& srcTable, uint32_t dstIndex, uint32_t srcIndex) {
break;
}
case TableKind::AnyRef: {
setAnyRef(dstIndex, srcTable.getAnyRef(srcIndex));
fillAnyRef(dstIndex, 1, srcTable.getAnyRef(srcIndex));
break;
}
case TableKind::AsmJS: {

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

@ -80,14 +80,19 @@ class Table : public ShareableBase<Table> {
// Only for function values. Raw pointer to the table.
uint8_t* functionBase() const;
// get/setFuncRef is allowed only on table-of-funcref.
// get/setAnyRef is allowed only on table-of-anyref.
// set/get/fillFuncRef is allowed only on table-of-funcref.
// get/fillAnyRef is allowed only on table-of-anyref.
// setNull is allowed on either.
const FunctionTableElem& getFuncRef(uint32_t index) const;
bool getFuncRef(JSContext* cx, uint32_t index,
MutableHandleFunction fun) const;
void setFuncRef(uint32_t index, void* code, const Instance* instance);
void fillFuncRef(uint32_t index, uint32_t fillCount, AnyRef ref,
JSContext* cx);
AnyRef getAnyRef(uint32_t index) const;
void setAnyRef(uint32_t index, AnyRef);
void fillAnyRef(uint32_t index, uint32_t fillCount, AnyRef ref);
void setNull(uint32_t index);

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

@ -1980,6 +1980,18 @@ struct Limits {
enum class TableKind { AnyRef, FuncRef, AsmJS };
static inline ValType ToElemValType(TableKind tk) {
switch (tk) {
case TableKind::AnyRef:
return ValType::AnyRef;
case TableKind::FuncRef:
return ValType::FuncRef;
case TableKind::AsmJS:
break;
}
MOZ_CRASH("not used for asm.js");
}
struct TableDesc {
TableKind kind;
bool importedOrExported;

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

@ -118,6 +118,75 @@ static int x_error_handler(Display*, XErrorEvent* ev) {
// care about leaking memory
extern "C" {
static int get_egl_status(char* buf, int bufsize) {
void* libegl = dlopen("libEGL.so.1", RTLD_LAZY);
if (!libegl) {
libegl = dlopen("libEGL.so", RTLD_LAZY);
}
if (!libegl) {
return 0;
}
typedef void* EGLDisplay;
typedef int EGLBoolean;
typedef int EGLint;
typedef void* (*PFNEGLGETPROCADDRESS)(const char*);
PFNEGLGETPROCADDRESS eglGetProcAddress =
cast<PFNEGLGETPROCADDRESS>(dlsym(libegl, "eglGetProcAddress"));
if (!eglGetProcAddress) {
dlclose(libegl);
return 0;
}
typedef EGLDisplay (*PFNEGLGETDISPLAYPROC)(void* native_display);
PFNEGLGETDISPLAYPROC eglGetDisplay =
cast<PFNEGLGETDISPLAYPROC>(eglGetProcAddress("eglGetDisplay"));
typedef EGLBoolean (*PFNEGLINITIALIZEPROC)(EGLDisplay dpy, EGLint * major,
EGLint * minor);
PFNEGLINITIALIZEPROC eglInitialize =
cast<PFNEGLINITIALIZEPROC>(eglGetProcAddress("eglInitialize"));
typedef EGLBoolean (*PFNEGLTERMINATEPROC)(EGLDisplay dpy);
PFNEGLTERMINATEPROC eglTerminate =
cast<PFNEGLTERMINATEPROC>(eglGetProcAddress("eglTerminate"));
typedef const char* (*PFNEGLGETDISPLAYDRIVERNAMEPROC)(EGLDisplay dpy);
PFNEGLGETDISPLAYDRIVERNAMEPROC eglGetDisplayDriverName =
cast<PFNEGLGETDISPLAYDRIVERNAMEPROC>(
eglGetProcAddress("eglGetDisplayDriverName"));
if (!eglGetDisplay || !eglInitialize || !eglTerminate ||
!eglGetDisplayDriverName) {
dlclose(libegl);
return 0;
}
EGLDisplay dpy = eglGetDisplay(nullptr);
if (!dpy) {
dlclose(libegl);
return 0;
}
EGLint major, minor;
if (!eglInitialize(dpy, &major, &minor)) {
dlclose(libegl);
return 0;
}
int length = 0;
const char* driDriver = eglGetDisplayDriverName(dpy);
if (driDriver) {
length = snprintf(buf, bufsize, "DRI_DRIVER\n%s\n", driDriver);
}
eglTerminate(dpy);
dlclose(libegl);
return length;
}
void glxtest() {
// we want to redirect to /dev/null stdout, stderr, and while we're at it,
// any PR logging file descriptors. To that effect, we redirect all positive
@ -255,7 +324,7 @@ void glxtest() {
vendorId &= 0xFFFF;
deviceId &= 0xFFFF;
length += snprintf(buf + length, bufsize,
length += snprintf(buf + length, bufsize - length,
"MESA_VENDOR_ID\n0x%04x\n"
"MESA_DEVICE_ID\n0x%04x\n"
"MESA_ACCELERATED\n%s\n"
@ -268,13 +337,15 @@ void glxtest() {
}
// From Mesa's GL/internal/dri_interface.h, to be used by DRI clients.
int gotDriDriver = 0;
typedef const char* (*PFNGLXGETSCREENDRIVERPROC)(Display * dpy, int scrNum);
PFNGLXGETSCREENDRIVERPROC glXGetScreenDriverProc =
cast<PFNGLXGETSCREENDRIVERPROC>(glXGetProcAddress("glXGetScreenDriver"));
if (glXGetScreenDriverProc) {
const char* driDriver = glXGetScreenDriverProc(dpy, DefaultScreen(dpy));
if (driDriver) {
length += snprintf(buf + length, bufsize, "DRI_DRIVER\n%s\n", driDriver);
gotDriDriver = 1;
length += snprintf(buf + length, bufsize - length, "DRI_DRIVER\n%s\n", driDriver);
if (length >= bufsize)
fatal_error("GL strings length too large for buffer size");
}
@ -304,6 +375,15 @@ void glxtest() {
dlclose(libgl);
// If we failed to get the driver name from X, try via EGL_MESA_query_driver.
// We are probably using Wayland.
if (!gotDriDriver) {
length += get_egl_status(buf + length, bufsize - length);
if (length >= bufsize) {
fatal_error("GL strings length too large for buffer size");
}
}
///// Finally write data to the pipe
mozilla::Unused << write(write_end_of_the_pipe, buf, length);
}

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

@ -274,9 +274,11 @@ void GfxInfo::GetData() {
}
} else if (glVendor.EqualsLiteral("NVIDIA Corporation")) {
CopyUTF16toUTF8(GfxDriverInfo::GetDeviceVendor(VendorNVIDIA), mVendorId);
mDriverVendor.AssignLiteral("nvidia/unknown");
// TODO: Use NV-CONTROL X11 extension to query Device ID and VRAM.
} else if (glVendor.EqualsLiteral("ATI Technologies Inc.")) {
CopyUTF16toUTF8(GfxDriverInfo::GetDeviceVendor(VendorATI), mVendorId);
mDriverVendor.AssignLiteral("ati/unknown");
// TODO: Look into ways to find the device ID on FGLRX.
} else {
NS_WARNING("Failed to detect GL vendor!");