Skip to content
This repository was archived by the owner on Jan 26, 2022. It is now read-only.

Coerce lane indexes with ToNumber(). #335

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 27 additions & 31 deletions src/ecmascript_simd.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,6 @@ function convertArray(buffer, array) {

// Utility functions.

function isInt32(o) {
return (o | 0) === o;
}

function isTypedArray(o) {
return (o instanceof Int8Array) ||
(o instanceof Uint8Array) ||
Expand Down Expand Up @@ -107,17 +103,17 @@ function clamp(a, min, max) {
// SIMD implementation functions

function simdCoerceIndex(index) {
index = +index;
if (index != Math.floor(index))
throw new RangeError("SIMD index must be an integer");
return index;
index = +index;
if (index != Math.floor(index))
throw new RangeError("SIMD index must be an integer");
return index;
}

function simdCheckLaneIndex(index, lanes) {
if (!isInt32(index))
throw new TypeError('Lane index must be an int32');
if (index < 0 || index >= lanes)
function simdCoerceLaneIndex(index, lanes) {
index = simdCoerceIndex(index);
if (!(index >= 0 && index < lanes))
throw new RangeError('Lane index must be in bounds');
return index;
}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe implement simdCoerceLaneIndex() using simdCoerceIndex(), just to avoid a little code duplication. It shouldn't matter that the index != Math.floor() check fails before the bounds check, I think.

// Global lanes array for constructing SIMD values.
Expand Down Expand Up @@ -155,7 +151,7 @@ function simdSplat(type, s) {

function simdReplaceLane(type, a, i, s) {
a = type.fn.check(a);
simdCheckLaneIndex(i, type.lanes);
i = simdCoerceLaneIndex(i, type.lanes);
for (var j = 0; j < type.lanes; j++)
lanes[j] = type.fn.extractLane(a, j);
lanes[i] = s;
Expand Down Expand Up @@ -196,8 +192,8 @@ function simdSelect(type, selector, a, b) {
function simdSwizzle(type, a, indices) {
a = type.fn.check(a);
for (var i = 0; i < indices.length; i++) {
simdCheckLaneIndex(indices[i], type.lanes);
lanes[i] = type.fn.extractLane(a, indices[i]);
var idx = simdCoerceLaneIndex(indices[i], type.lanes);
lanes[i] = type.fn.extractLane(a, idx);
}
return simdCreate(type);
}
Expand All @@ -206,10 +202,10 @@ function simdShuffle(type, a, b, indices) {
a = type.fn.check(a);
b = type.fn.check(b);
for (var i = 0; i < indices.length; i++) {
simdCheckLaneIndex(indices[i], 2 * type.lanes);
lanes[i] = indices[i] < type.lanes ?
type.fn.extractLane(a, indices[i]) :
type.fn.extractLane(b, indices[i] - type.lanes);
var idx = simdCoerceLaneIndex(indices[i], 2 * type.lanes);
lanes[i] = idx < type.lanes ?
type.fn.extractLane(a, idx) :
type.fn.extractLane(b, idx - type.lanes);
}
return simdCreate(type);
}
Expand Down Expand Up @@ -355,7 +351,7 @@ if (typeof SIMD.Float32x4 === "undefined" ||

SIMD.Float32x4.extractLane = function(v, i) {
v = SIMD.Float32x4.check(v);
simdCheckLaneIndex(i, 4);
i = simdCoerceLaneIndex(i, 4);
return v.s_[i];
}
}
Expand Down Expand Up @@ -386,7 +382,7 @@ if (typeof SIMD.Int32x4 === "undefined" ||

SIMD.Int32x4.extractLane = function(v, i) {
v = SIMD.Int32x4.check(v);
simdCheckLaneIndex(i, 4);
i = simdCoerceLaneIndex(i, 4);
return v.s_[i];
}
}
Expand Down Expand Up @@ -415,7 +411,7 @@ if (typeof SIMD.Int16x8 === "undefined" ||

SIMD.Int16x8.extractLane = function(v, i) {
v = SIMD.Int16x8.check(v);
simdCheckLaneIndex(i, 8);
i = simdCoerceLaneIndex(i, 8);
return v.s_[i];
}
}
Expand Down Expand Up @@ -447,7 +443,7 @@ if (typeof SIMD.Int8x16 === "undefined" ||

SIMD.Int8x16.extractLane = function(v, i) {
v = SIMD.Int8x16.check(v);
simdCheckLaneIndex(i, 16);
i = simdCoerceLaneIndex(i, 16);
return v.s_[i];
}
}
Expand Down Expand Up @@ -480,7 +476,7 @@ if (typeof SIMD.Uint32x4 === "undefined" ||

SIMD.Uint32x4.extractLane = function(v, i) {
v = SIMD.Uint32x4.check(v);
simdCheckLaneIndex(i, 4);
i = simdCoerceLaneIndex(i, 4);
return v.s_[i];
}
}
Expand Down Expand Up @@ -509,7 +505,7 @@ if (typeof SIMD.Uint16x8 === "undefined" ||

SIMD.Uint16x8.extractLane = function(v, i) {
v = SIMD.Uint16x8.check(v);
simdCheckLaneIndex(i, 8);
i = simdCoerceLaneIndex(i, 8);
return v.s_[i];
}
}
Expand Down Expand Up @@ -541,7 +537,7 @@ if (typeof SIMD.Uint8x16 === "undefined" ||

SIMD.Uint8x16.extractLane = function(v, i) {
v = SIMD.Uint8x16.check(v);
simdCheckLaneIndex(i, 16);
i = simdCoerceLaneIndex(i, 16);
return v.s_[i];
}
}
Expand Down Expand Up @@ -574,7 +570,7 @@ if (typeof SIMD.Bool32x4 === "undefined" ||

SIMD.Bool32x4.extractLane = function(v, i) {
v = SIMD.Bool32x4.check(v);
simdCheckLaneIndex(i, 4);
i = simdCoerceLaneIndex(i, 4);
return v.s_[i];
}
}
Expand All @@ -591,7 +587,7 @@ if (typeof SIMD.Bool16x8 === "undefined" ||

SIMD.Bool16x8.extractLane = function(v, i) {
v = SIMD.Bool16x8.check(v);
simdCheckLaneIndex(i, 8);
i = simdCoerceLaneIndex(i, 8);
return v.s_[i];
}
}
Expand All @@ -611,7 +607,7 @@ if (typeof SIMD.Bool8x16 === "undefined" ||

SIMD.Bool8x16.extractLane = function(v, i) {
v = SIMD.Bool8x16.check(v);
simdCheckLaneIndex(i, 16);
i = simdCoerceLaneIndex(i, 16);
return v.s_[i];
}
}
Expand Down Expand Up @@ -828,7 +824,7 @@ if (typeof simdPhase2 !== 'undefined') {

SIMD.Float64x2.extractLane = function(v, i) {
v = SIMD.Float64x2.check(v);
simdCheckLaneIndex(i, 2);
i = simdCoerceLaneIndex(i, 2);
return v.s_[i];
}
}
Expand Down Expand Up @@ -857,7 +853,7 @@ if (typeof simdPhase2 !== 'undefined') {

SIMD.Bool64x2.extractLane = function(v, i) {
v = SIMD.Bool64x2.check(v);
simdCheckLaneIndex(i, 2);
i = simdCoerceLaneIndex(i, 2);
return v.s_[i];
}
}
Expand Down
77 changes: 53 additions & 24 deletions src/ecmascript_simd_tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -420,15 +420,30 @@ function testReplaceLane(type) {
}
}

// Test lane index coercion.
// ToNumber (index) must be an integer in range.
function validLaneIndex(testIndex) {
var v = simdConvert(type.interestingValues[type.interestingValues.length - 1]);
var result = type.fn.replaceLane(a, testIndex, v);
checkValue(type, result,
function(i) {
return i == testIndex ? v :type.fn.extractLane(a, i);
});
}
validLaneIndex(null);
validLaneIndex(false);
validLaneIndex(true);
validLaneIndex("0");
validLaneIndex("00");
validLaneIndex(" +1e0");

function testIndexCheck(index) {
throws(function() { type.fn.replaceLane(a, index, 0); });
}
testIndexCheck(type.lanes);
testIndexCheck(13.37);
testIndexCheck(null);
testIndexCheck(undefined);
testIndexCheck({});
testIndexCheck(true);
testIndexCheck('yo');
testIndexCheck(-1);
testIndexCheck(128);
Expand Down Expand Up @@ -578,22 +593,29 @@ function testSwizzle(type) {
var result = type.fn.swizzle.apply(type.fn, [a].concat(indices));
checkValue(type, result, function(index) { return type.fn.extractLane(a, type.lanes - index - 1); });

function testIndexCheck(index) {
function testIndexCheck(expectValid, index) {
for (var i = 0; i < type.lanes; i++) {
var args = [a].concat(indices);
args[i + 1] = index;
throws(function() { type.fn.swizzle.apply(type.fn, args); });
if (expectValid)
type.fn.swizzle.apply(type.fn, args);
else
throws(function() { type.fn.swizzle.apply(type.fn, args); });
}
}
testIndexCheck(type.lanes);
testIndexCheck(13.37);
testIndexCheck(null);
testIndexCheck(undefined);
testIndexCheck({});
testIndexCheck(true);
testIndexCheck('yo');
testIndexCheck(-1);
testIndexCheck(128);
testIndexCheck(true, null);
testIndexCheck(true, true);
testIndexCheck(true, false);
testIndexCheck(true, "0");
testIndexCheck(true, "00");
testIndexCheck(true, " +1e0");
testIndexCheck(false, type.lanes);
testIndexCheck(false, 13.37);
testIndexCheck(false, undefined);
testIndexCheck(false, {});
testIndexCheck(false, 'yo');
testIndexCheck(false, -1);
testIndexCheck(false, 128);
}

function testShuffle(type) {
Expand Down Expand Up @@ -621,22 +643,29 @@ function testShuffle(type) {
var result = type.fn.shuffle.apply(type.fn, [a, b].concat(indices));
checkValue(type, result, function(index) { return type.fn.extractLane(b, index); });

function testIndexCheck(index) {
function testIndexCheck(expectValid, index) {
for (var i = 0; i < type.lanes; i++) {
var args = [a, b].concat(indices);
args[i + 2] = index;
throws(function() { type.fn.shuffle.apply(type.fn, args); });
if (expectValid)
type.fn.shuffle.apply(type.fn, args);
else
throws(function() { type.fn.shuffle.apply(type.fn, args); });
}
}
testIndexCheck(2 * type.lanes);
testIndexCheck(13.37);
testIndexCheck(null);
testIndexCheck(undefined);
testIndexCheck({});
testIndexCheck(true);
testIndexCheck('yo');
testIndexCheck(-1);
testIndexCheck(128);
testIndexCheck(true, null);
testIndexCheck(true, true);
testIndexCheck(true, false);
testIndexCheck(true, "0");
testIndexCheck(true, "00");
testIndexCheck(true, " +1e0");
testIndexCheck(false, 2 * type.lanes);
testIndexCheck(false, 13.37);
testIndexCheck(false, undefined);
testIndexCheck(false, {});
testIndexCheck(false, 'yo');
testIndexCheck(false, -1);
testIndexCheck(false, 128);
}

function testLoad(type, name, count) {
Expand Down