Atomics.waitAsync: validate array type; waiter list position, notify before timeout

This commit is contained in:
Rick Waldron 2020-04-15 16:55:47 -04:00
parent 161ce480d1
commit d7e4de1484
16 changed files with 554 additions and 21 deletions

View File

@ -58,6 +58,6 @@ Promise.all([
Atomics.waitAsync(i32a, 0, 0, toPrimitive).value,
]).then(outcomes => {
assert.sameValue(outcomes[0], 'timed-out');
assert.sameValue(outcomes[0], 'timed-out');
assert.sameValue(outcomes[0], 'timed-out');
assert.sameValue(outcomes[1], 'timed-out');
assert.sameValue(outcomes[2], 'timed-out');
}, $DONE).then($DONE, $DONE);

View File

@ -23,9 +23,9 @@ const i32a = new Int32Array(
Promise.all([
Atomics.waitAsync(i32a, 0, 0, -1).value,
]).then(outcomes => {
]).then(([outcome]) => {
assert.sameValue(
outcomes[0],
outcome,
'timed-out',
'Atomics.waitAsync(i32a, 0, 0, -1).value resolves to "timed-out"'
);

View File

@ -58,6 +58,6 @@ Promise.all([
Atomics.waitAsync(i32a, 0, 0, toPrimitive).value,
]).then(outcomes => {
assert.sameValue(outcomes[0], "timed-out");
assert.sameValue(outcomes[0], "timed-out");
assert.sameValue(outcomes[0], "timed-out");
assert.sameValue(outcomes[1], "timed-out");
assert.sameValue(outcomes[2], "timed-out");
}, $DONE).then($DONE, $DONE);

View File

@ -66,6 +66,6 @@ Promise.all([
Atomics.waitAsync(i32a, 0, 0, toPrimitive).value,
]).then(outcomes => {
assert.sameValue(outcomes[0], "timed-out");
assert.sameValue(outcomes[0], "timed-out");
assert.sameValue(outcomes[0], "timed-out");
assert.sameValue(outcomes[1], "timed-out");
assert.sameValue(outcomes[2], "timed-out");
}, $DONE).then($DONE, $DONE);

View File

@ -41,8 +41,8 @@ $262.agent.start(`
const i32a = new Int32Array(sab);
Atomics.add(i32a, ${RUNNING}, 1);
let status1 = ';
let status2 = ';
let status1 = '';
let status2 = '';
try {
Atomics.wait(i32a, 0, 0, poisonedValueOf);

View File

@ -42,6 +42,6 @@ Promise.all([
Atomics.waitAsync(i32a, 0, 0, toPrimitive).value,
]).then(outcomes => {
assert.sameValue(outcomes[0], 'timed-out');
assert.sameValue(outcomes[0], 'timed-out');
assert.sameValue(outcomes[0], 'timed-out');
assert.sameValue(outcomes[1], 'timed-out');
assert.sameValue(outcomes[2], 'timed-out');
}, $DONE).then($DONE, $DONE);

View File

@ -4,7 +4,7 @@
/*---
esid: sec-atomics.waitasync
description: >
Undefined timeout arg should result in an infinite timeout
Undefined timeout arg is coerced to zero
info: |
Atomics.waitAsync( typedArray, index, value, timeout )
@ -64,12 +64,12 @@ $262.agent.safeBroadcastAsync(i32a, RUNNING, NUMAGENT).then(async (agentCount) =
'Atomics.notify(i32a, WAIT_INDEX, NOTIFYCOUNT) returns the value of `NOTIFYCOUNT` (2)'
);
Promise.all([
$262.agent.getReportAsync(),
$262.agent.getReportAsync(),
]).then(reports => {
reports.sort();
assert.sameValue(reports[0], 'A ok', 'The value of reports[0] is "A ok"');
assert.sameValue(reports[1], 'B ok', 'The value of reports[1] is "B ok"');
}).then($DONE, $DONE);
const reports = [
await $262.agent.getReportAsync(),
await $262.agent.getReportAsync(),
];
reports.sort();
assert.sameValue(reports[0], 'A ok', 'The value of reports[0] is "A ok"');
assert.sameValue(reports[1], 'B ok', 'The value of reports[1] is "B ok"');
}).then($DONE, $DONE);

View File

@ -0,0 +1,62 @@
// Copyright (C) 2020 Rick Waldron. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-atomics.waitasync
description: >
Undefined timeout arg is coerced to zero
info: |
Atomics.waitAsync( typedArray, index, value, timeout )
1. Return DoWait(async, typedArray, index, value, timeout).
DoWait ( mode, typedArray, index, value, timeout )
6. Let q be ? ToNumber(timeout).
...
Undefined Return NaN.
5.If q is NaN, let t be +, else let t be max(q, 0)
flags: [async]
includes: [atomicsHelper.js]
features: [Atomics.waitAsync, SharedArrayBuffer, TypedArray, Atomics]
---*/
const i32a = new Int32Array(
new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * 4)
);
$262.agent.start(`
$262.agent.receiveBroadcast(async (sab) => {
var i32a = new Int32Array(sab);
$262.agent.sleep(1000);
Atomics.notify(i32a, 0, 4);
$262.agent.leaving();
});
`);
$262.agent.safeBroadcast(i32a);
const valueOf = {
valueOf() {
return undefined;
}
};
const toPrimitive = {
[Symbol.toPrimitive]() {
return undefined;
}
};
Promise.all([
Atomics.waitAsync(i32a, 0, 0).value,
Atomics.waitAsync(i32a, 0, 0, undefined).value,
Atomics.waitAsync(i32a, 0, 0, valueOf).value,
Atomics.waitAsync(i32a, 0, 0, toPrimitive).value,
]).then(outcomes => {
assert.sameValue(outcomes[0], 'ok');
assert.sameValue(outcomes[1], 'ok');
assert.sameValue(outcomes[2], 'ok');
assert.sameValue(outcomes[3], 'ok');
}, $DONE).then($DONE, $DONE);

View File

@ -0,0 +1,76 @@
// Copyright (C) 2020 Rick Waldron. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-atomics.waitasync
description: >
Undefined index arg is coerced to zero
info: |
Atomics.waitAsync( typedArray, index, value, timeout )
1. Return DoWait(async, typedArray, index, value, timeout).
DoWait ( mode, typedArray, index, value, timeout )
2. Let i be ? ValidateAtomicAccess(typedArray, index).
...
2.Let accessIndex be ? ToIndex(requestIndex).
9.If IsSharedArrayBuffer(buffer) is false, throw a TypeError exception.
...
3.If bufferData is a Data Block, return false
If value is undefined, then
Let index be 0.
flags: [async]
includes: [atomicsHelper.js]
features: [Atomics.waitAsync, SharedArrayBuffer, TypedArray, Atomics]
---*/
const WAIT_INDEX = 0;
const RUNNING = 1;
const NUMAGENT = 2;
const NOTIFYCOUNT = 2;
$262.agent.start(`
$262.agent.receiveBroadcast(async (sab) => {
var i32a = new Int32Array(sab);
Atomics.add(i32a, ${RUNNING}, 1);
$262.agent.report("A " + (await Atomics.waitAsync(i32a, undefined, 0).value));
$262.agent.leaving();
});
`);
$262.agent.start(`
$262.agent.receiveBroadcast(async (sab) => {
var i32a = new Int32Array(sab);
Atomics.add(i32a, ${RUNNING}, 1);
$262.agent.report("B " + (await Atomics.waitAsync(i32a, undefined, 0).value));
$262.agent.leaving();
});
`);
const i32a = new Int32Array(
new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * 4)
);
$262.agent.safeBroadcastAsync(i32a, RUNNING, NUMAGENT).then(async (agentCount) => {
assert.sameValue(agentCount, NUMAGENT);
assert.sameValue(
Atomics.notify(i32a, WAIT_INDEX, NOTIFYCOUNT),
NOTIFYCOUNT,
'Atomics.notify(i32a, WAIT_INDEX, NOTIFYCOUNT) returns the value of `NOTIFYCOUNT` (2)'
);
const reports = [
await $262.agent.getReportAsync(),
await $262.agent.getReportAsync(),
];
reports.sort();
assert.sameValue(reports[0], 'A ok', 'The value of reports[0] is "A ok"');
assert.sameValue(reports[1], 'B ok', 'The value of reports[1] is "B ok"');
}).then($DONE, $DONE);

View File

@ -0,0 +1,49 @@
// Copyright (C) 2020 Rick Waldron. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-atomics.waitasync
description: >
TypedArray type is validated before `index` argument is coerced.
info: |
1. Return DoWait(async, typedArray, index, value, timeout).
DoWait ( mode, typedArray, index, value, timeout )
1. Let buffer be ? ValidateSharedIntegerTypedArray(typedArray, true).
ValidateSharedIntegerTypedArray ( typedArray [ , waitable ] )
1. If waitable is not present, set waitable to false.
2. Perform ? RequireInternalSlot(typedArray, [[TypedArrayName]]).
3. Let typeName be typedArray.[[TypedArrayName]].
4. Let type be the Element Type value in Table 61 for typeName.
5. If waitable is true, then
a. If typeName is not "Int32Array" or "BigInt64Array", throw a TypeError exception.
6. Else,
a. If ! IsUnclampedIntegerElementType(type) is false and ! IsBigIntElementType(type) is false, throw a TypeError exception.
7. Assert: typedArray has a [[ViewedArrayBuffer]] internal slot.
8. Let buffer be typedArray.[[ViewedArrayBuffer]].
9. If IsSharedArrayBuffer(buffer) is false, throw a TypeError exception.
10. Return buffer.
features: [Atomics.waitAsync, Atomics, TypedArray, SharedArrayBuffer]
---*/
const index = {
valueOf() {
throw new Test262Error("index coerced");
}
};
const nonSharedArrayTypes = [
Int8Array, Uint8Array, Int16Array, Uint16Array, Uint32Array,
Uint8ClampedArray, Float32Array, Float64Array
];
for (const nonSharedArrayType of nonSharedArrayTypes) {
const typedArray = new nonSharedArrayType(new SharedArrayBuffer(8));
assert.throws(TypeError, function() {
Atomics.waitAsync(typedArray, index, 0, 0);
});
}

View File

@ -0,0 +1,48 @@
// Copyright (C) 2020 Rick Waldron. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-atomics.waitasync
description: >
TypedArray type is validated before `timeout` argument is coerced.
info: |
1. Return DoWait(async, typedArray, index, value, timeout).
DoWait ( mode, typedArray, index, value, timeout )
1. Let buffer be ? ValidateSharedIntegerTypedArray(typedArray, true).
ValidateSharedIntegerTypedArray ( typedArray [ , waitable ] )
1. If waitable is not present, set waitable to false.
2. Perform ? RequireInternalSlot(typedArray, [[TypedArrayName]]).
3. Let typeName be typedArray.[[TypedArrayName]].
4. Let type be the Element Type value in Table 61 for typeName.
5. If waitable is true, then
a. If typeName is not "Int32Array" or "BigInt64Array", throw a TypeError exception.
6. Else,
a. If ! IsUnclampedIntegerElementType(type) is false and ! IsBigIntElementType(type) is false, throw a TypeError exception.
7. Assert: typedArray has a [[ViewedArrayBuffer]] internal slot.
8. Let buffer be typedArray.[[ViewedArrayBuffer]].
9. If IsSharedArrayBuffer(buffer) is false, throw a TypeError exception.
10. Return buffer.
features: [Atomics.waitAsync, Atomics, TypedArray, SharedArrayBuffer]
---*/
const timeout = {
valueOf() {
throw new Test262Error("timeout coerced");
}
};
const nonSharedArrayTypes = [
Int8Array, Uint8Array, Int16Array, Uint16Array, Uint32Array,
Uint8ClampedArray, Float32Array, Float64Array
];
for (const nonSharedArrayType of nonSharedArrayTypes) {
const typedArray = new nonSharedArrayType(new SharedArrayBuffer(8));
assert.throws(TypeError, function() {
Atomics.waitAsync(typedArray, 0, 0, timeout);
});
}

View File

@ -0,0 +1,49 @@
// Copyright (C) 2020 Rick Waldron. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-atomics.notify
description: >
TypedArray type is validated before `value` argument is coerced.
info: |
1. Return DoWait(async, typedArray, index, value, timeout).
DoWait ( mode, typedArray, index, value, timeout )
1. Let buffer be ? ValidateSharedIntegerTypedArray(typedArray, true).
ValidateSharedIntegerTypedArray ( typedArray [ , waitable ] )
1. If waitable is not present, set waitable to false.
2. Perform ? RequireInternalSlot(typedArray, [[TypedArrayName]]).
3. Let typeName be typedArray.[[TypedArrayName]].
4. Let type be the Element Type value in Table 61 for typeName.
5. If waitable is true, then
a. If typeName is not "Int32Array" or "BigInt64Array", throw a TypeError exception.
6. Else,
a. If ! IsUnclampedIntegerElementType(type) is false and ! IsBigIntElementType(type) is false, throw a TypeError exception.
7. Assert: typedArray has a [[ViewedArrayBuffer]] internal slot.
8. Let buffer be typedArray.[[ViewedArrayBuffer]].
9. If IsSharedArrayBuffer(buffer) is false, throw a TypeError exception.
10. Return buffer.
features: [Atomics.waitAsync, Atomics, TypedArray, SharedArrayBuffer]
---*/
const value = {
valueOf() {
throw new Test262Error("value coerced");
}
};
const nonSharedArrayTypes = [
Int8Array, Uint8Array, Int16Array, Uint16Array, Uint32Array,
Uint8ClampedArray, Float32Array, Float64Array
];
for (const nonSharedArrayType of nonSharedArrayTypes) {
const typedArray = new nonSharedArrayType(new SharedArrayBuffer(8));
assert.throws(TypeError, function() {
Atomics.wait(typedArray, 0, value, 0);
});
}

View File

@ -0,0 +1,64 @@
// Copyright (C) 2020 Rick Waldron. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-atomics.waitasync
description: >
Returns "not-equal" when value arg does not match an index in the typedArray
info: |
Atomics.waitAsync( typedArray, index, value, timeout )
1. Return DoWait(async, typedArray, index, value, timeout).
DoWait ( mode, typedArray, index, value, timeout )
16. Let w be ! AtomicLoad(typedArray, i).
17. If v is not equal to w, then
a. Perform LeaveCriticalSection(WL).
b. If mode is sync, then
i. Return the String "not-equal".
c. Perform ! Call(capability.[[Resolve]], undefined, « "not-equal" »).
d. Return promiseCapability.[[Promise]].
flags: [async]
includes: [atomicsHelper.js]
features: [Atomics.waitAsync, SharedArrayBuffer, TypedArray]
---*/
const RUNNING = 1;
const value = 42;
$262.agent.start(`
$262.agent.receiveBroadcast(function(sab) {
const i32a = new Int32Array(sab);
Atomics.add(i32a, ${RUNNING}, 1);
$262.agent.report(Atomics.store(i32a, 0, ${value}));
$262.agent.report(Atomics.waitAsync(i32a, 0, 0).value);
$262.agent.leaving();
});
`);
const i32a = new Int32Array(
new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * 4)
);
$262.agent.safeBroadcastAsync(i32a, RUNNING, 1).then(async (agentCount) => {
assert.sameValue(agentCount, 1);
assert.sameValue(
await $262.agent.getReportAsync(),
value.toString(),
'Atomics.store(i32a, 0, ${value}) returns 42'
);
assert.sameValue(
await $262.agent.getReportAsync(),
'not-equal',
'Atomics.waitAsync(i32a, 0, 0).value resolves to "not-equal"'
);
assert.sameValue(
Atomics.notify(i32a, 0, 1),
0,
'Atomics.notify(i32a, 0, 1) returns 0 (nothing to notify)'
);
}).then($DONE, $DONE);

View File

@ -0,0 +1,49 @@
// Copyright (C) 2020 Rick Waldron. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-atomics.waitasync
description: >
Returns "not-equal" when value arg does not match an index in the typedArray
info: |
Atomics.waitAsync( typedArray, index, value, timeout )
1. Return DoWait(async, typedArray, index, value, timeout).
DoWait ( mode, typedArray, index, value, timeout )
16. Let w be ! AtomicLoad(typedArray, i).
17. If v is not equal to w, then
a. Perform LeaveCriticalSection(WL).
b. If mode is sync, then
i. Return the String "not-equal".
c. Perform ! Call(capability.[[Resolve]], undefined, « "not-equal" »).
d. Return promiseCapability.[[Promise]].
flags: [async]
includes: [atomicsHelper.js]
features: [Atomics.waitAsync, SharedArrayBuffer, TypedArray]
---*/
const i32a = new Int32Array(
new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * 4)
);
const valueOf = {
valueOf() {
return undefined;
}
};
const toPrimitive = {
[Symbol.toPrimitive]() {
return undefined;
}
};
Promise.all([
Atomics.store(i32a, 0, 42),
Atomics.waitAsync(i32a, 0, 0).value,
]).then(outcomes => {
assert.sameValue(outcomes[0], 42);
assert.sameValue(outcomes[1], 'not-equal');
}, $DONE).then($DONE, $DONE);

View File

@ -0,0 +1,82 @@
// Copyright (C) 2020 Rick Waldron. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-atomics.waitasync
description: >
Get the correct WaiterList
info: |
Atomics.waitAsync( typedArray, index, value, timeout )
1. Return DoWait(async, typedArray, index, value, timeout).
DoWait ( mode, typedArray, index, value, timeout )
11. Let indexedPosition be (i × 4) + offset.
12. Let WL be GetWaiterList(block, indexedPosition).
GetWaiterList( block, i )
...
4. Return the WaiterList that is referenced by the pair (block, i).
flags: [async]
includes: [atomicsHelper.js]
features: [Atomics.waitAsync, SharedArrayBuffer, TypedArray, Atomics]
---*/
const NUMAGENT = 2;
const RUNNING = 4;
$262.agent.start(`
$262.agent.receiveBroadcast(async (sab) => {
const i32a = new Int32Array(sab);
Atomics.add(i32a, ${RUNNING}, 1);
// Wait on index 0
$262.agent.report(await Atomics.waitAsync(i32a, 0, 0, Infinity).value);
$262.agent.leaving();
});
`);
$262.agent.start(`
$262.agent.receiveBroadcast(async (sab) => {
const i32a = new Int32Array(sab);
Atomics.add(i32a, ${RUNNING}, 1);
// Wait on index 2
$262.agent.report(await Atomics.waitAsync(i32a, 2, 0, Infinity).value);
$262.agent.leaving();
});
`);
const i32a = new Int32Array(
new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * 5)
);
$262.agent.safeBroadcastAsync(i32a, RUNNING, NUMAGENT).then(async (agentCount) => {
assert.sameValue(agentCount, NUMAGENT);
// Notify index 1, notifies nothing
assert.sameValue(Atomics.notify(i32a, 1), 0, 'Atomics.notify(i32a, 1) returns 0');
// Notify index 3, notifies nothing
assert.sameValue(Atomics.notify(i32a, 3), 0, 'Atomics.notify(i32a, 3) returns 0');
// Notify index 2, notifies 1
assert.sameValue(Atomics.notify(i32a, 2), 1, 'Atomics.notify(i32a, 2) returns 1');
assert.sameValue(
await $262.agent.getReportAsync(),
'ok',
'await Atomics.waitAsync(i32a, 0, 0, Infinity).value resolves to "ok"'
);
// Notify index 0, notifies 1
assert.sameValue(Atomics.notify(i32a, 0), 1, 'Atomics.notify(i32a, 0) returns 1');
assert.sameValue(
await $262.agent.getReportAsync(),
'ok',
'await Atomics.waitAsync(i32a, 2, 0, Infinity).value resolves to "ok"'
);
}).then($DONE, $DONE);

View File

@ -0,0 +1,54 @@
// Copyright (C) 2020 Rick Waldron. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-atomics.waitasync
description: >
Test that Atomics.waitAsync returns the right result when it was awoken before
a timeout
flags: [async]
includes: [atomicsHelper.js]
features: [Atomics.waitAsync, SharedArrayBuffer, TypedArray, Atomics]
---*/
const RUNNING = 1;
const TIMEOUT = $262.agent.timeouts.huge;
const i32a = new Int32Array(
new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * 4)
);
$262.agent.start(`
$262.agent.receiveBroadcast(async (sab) => {
const i32a = new Int32Array(sab);
Atomics.add(i32a, ${RUNNING}, 1);
const before = $262.agent.monotonicNow();
const unpark = await Atomics.waitAsync(i32a, 0, 0, ${TIMEOUT}).value;
const duration = $262.agent.monotonicNow() - before;
$262.agent.report(duration);
$262.agent.report(unpark);
$262.agent.leaving();
});
`);
$262.agent.safeBroadcastAsync(i32a, RUNNING, 1).then(async (agentCount) => {
assert.sameValue(agentCount, 1);
assert.sameValue(Atomics.notify(i32a, 0), 1, 'Atomics.notify(i32a, 0) returns 1');
const lapse = await $262.agent.getReportAsync();
assert(
lapse < TIMEOUT,
'The result of `(lapse >= TIMEOUT)` is true'
);
const result = await $262.agent.getReportAsync();
assert.sameValue(
result,
'ok',
'await Atomics.waitAsync(i32a, 0, 0, ${TIMEOUT}).value resolves to "ok"'
);
assert.sameValue(Atomics.notify(i32a, 0), 0, 'Atomics.notify(i32a, 0) returns 0');
}).then($DONE, $DONE);