Revert "Bug 1964692 - Part 8: Add fast-path when (Shared)ArrayBuffer species fuses are intact. r=jandem"
This reverts commitf206dc3f94. Revert "Bug 1964692 - Part 7: Add fuses for ArrayBuffer and SharedArrayBuffer species. r=jandem" This reverts commit48314b5b5f. Revert "Bug 1964692 - Part 6: Remove self-hosting functions for SharedArrayBufferSlice. r=jandem" This reverts commite854beadd7. Revert "Bug 1964692 - Part 5: Implement SharedArrayBuffer.prototype.slice in C++. r=jandem" This reverts commitc5fc89b3f3. Revert "Bug 1964692 - Part 4: Remove unused built-in object kinds. r=jandem" This reverts commit85491af690. Revert "Bug 1964692 - Part 3: Remove self-hosting functions for ArrayBufferSlice. r=jandem" This reverts commit6cfc2c0ecf. Revert "Bug 1964692 - Part 2: Implement ArrayBuffer.prototype.slice in C++. r=jandem" This reverts commit792883453d. Revert "Bug 1964692 - Part 1: Move ToIntegerIndex to jsnum. r=jandem" This reverts commitfd25a9d5fa.
This commit is contained in:
committed by
agoloman@mozilla.com
parent
f206dc3f94
commit
2a61527c1a
@@ -1322,6 +1322,123 @@ function IterableToList(items, method) {
|
|||||||
return values;
|
return values;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ES2020 draft rev dc1e21c454bd316810be1c0e7af0131a2d7f38e9
|
||||||
|
// 24.1.4.3 ArrayBuffer.prototype.slice ( start, end )
|
||||||
|
function ArrayBufferSlice(start, end) {
|
||||||
|
// Step 1.
|
||||||
|
var O = this;
|
||||||
|
|
||||||
|
// Steps 2-3,
|
||||||
|
// This function is not generic.
|
||||||
|
if (!IsObject(O) || (O = GuardToArrayBuffer(O)) === null) {
|
||||||
|
return callFunction(
|
||||||
|
CallArrayBufferMethodIfWrapped,
|
||||||
|
this,
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
"ArrayBufferSlice"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 4.
|
||||||
|
if (IsDetachedBuffer(O)) {
|
||||||
|
ThrowTypeError(JSMSG_TYPED_ARRAY_DETACHED);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 5.
|
||||||
|
var len = ArrayBufferByteLength(O);
|
||||||
|
|
||||||
|
// Step 6.
|
||||||
|
var relativeStart = ToInteger(start);
|
||||||
|
|
||||||
|
// Step 7.
|
||||||
|
var first =
|
||||||
|
relativeStart < 0
|
||||||
|
? std_Math_max(len + relativeStart, 0)
|
||||||
|
: std_Math_min(relativeStart, len);
|
||||||
|
|
||||||
|
// Step 8.
|
||||||
|
var relativeEnd = end === undefined ? len : ToInteger(end);
|
||||||
|
|
||||||
|
// Step 9.
|
||||||
|
var final =
|
||||||
|
relativeEnd < 0
|
||||||
|
? std_Math_max(len + relativeEnd, 0)
|
||||||
|
: std_Math_min(relativeEnd, len);
|
||||||
|
|
||||||
|
// Step 10.
|
||||||
|
var newLen = std_Math_max(final - first, 0);
|
||||||
|
|
||||||
|
// Step 11
|
||||||
|
var ctor = SpeciesConstructor(O, GetBuiltinConstructor("ArrayBuffer"));
|
||||||
|
|
||||||
|
// Step 12.
|
||||||
|
var new_ = constructContentFunction(ctor, ctor, newLen);
|
||||||
|
|
||||||
|
// Steps 13-15.
|
||||||
|
var isWrapped = false;
|
||||||
|
var newBuffer;
|
||||||
|
if ((newBuffer = GuardToArrayBuffer(new_)) !== null) {
|
||||||
|
// Step 15.
|
||||||
|
if (IsDetachedBuffer(newBuffer)) {
|
||||||
|
ThrowTypeError(JSMSG_TYPED_ARRAY_DETACHED);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
newBuffer = new_;
|
||||||
|
|
||||||
|
// Steps 13-14.
|
||||||
|
if (!IsWrappedArrayBuffer(newBuffer)) {
|
||||||
|
ThrowTypeError(JSMSG_NON_ARRAY_BUFFER_RETURNED);
|
||||||
|
}
|
||||||
|
|
||||||
|
isWrapped = true;
|
||||||
|
|
||||||
|
// Step 15.
|
||||||
|
if (
|
||||||
|
callFunction(
|
||||||
|
CallArrayBufferMethodIfWrapped,
|
||||||
|
newBuffer,
|
||||||
|
"IsDetachedBufferThis"
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
ThrowTypeError(JSMSG_TYPED_ARRAY_DETACHED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 16.
|
||||||
|
if (newBuffer === O) {
|
||||||
|
ThrowTypeError(JSMSG_SAME_ARRAY_BUFFER_RETURNED);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 17.
|
||||||
|
var actualLen = PossiblyWrappedArrayBufferByteLength(newBuffer);
|
||||||
|
if (actualLen < newLen) {
|
||||||
|
ThrowTypeError(JSMSG_SHORT_ARRAY_BUFFER_RETURNED, newLen, actualLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Steps 18-19.
|
||||||
|
if (IsDetachedBuffer(O)) {
|
||||||
|
ThrowTypeError(JSMSG_TYPED_ARRAY_DETACHED);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Steps 20-22.
|
||||||
|
//
|
||||||
|
// Reacquire the length in case the buffer has been resized.
|
||||||
|
var currentLen = ArrayBufferByteLength(O);
|
||||||
|
|
||||||
|
if (first < currentLen) {
|
||||||
|
var count = std_Math_min(newLen, currentLen - first);
|
||||||
|
ArrayBufferCopyData(newBuffer, 0, O, first, count, isWrapped);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 23.
|
||||||
|
return newBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
function IsDetachedBufferThis() {
|
||||||
|
return IsDetachedBuffer(this);
|
||||||
|
}
|
||||||
|
|
||||||
// ES 2016 draft Mar 25, 2016 24.1.3.3.
|
// ES 2016 draft Mar 25, 2016 24.1.3.3.
|
||||||
function $ArrayBufferSpecies() {
|
function $ArrayBufferSpecies() {
|
||||||
// Step 1.
|
// Step 1.
|
||||||
@@ -1336,6 +1453,83 @@ function $SharedArrayBufferSpecies() {
|
|||||||
}
|
}
|
||||||
SetCanonicalName($SharedArrayBufferSpecies, "get [Symbol.species]");
|
SetCanonicalName($SharedArrayBufferSpecies, "get [Symbol.species]");
|
||||||
|
|
||||||
|
// ES2020 draft rev dc1e21c454bd316810be1c0e7af0131a2d7f38e9
|
||||||
|
// 24.2.4.3 SharedArrayBuffer.prototype.slice ( start, end )
|
||||||
|
function SharedArrayBufferSlice(start, end) {
|
||||||
|
// Step 1.
|
||||||
|
var O = this;
|
||||||
|
|
||||||
|
// Steps 2-3.
|
||||||
|
// This function is not generic.
|
||||||
|
if (!IsObject(O) || (O = GuardToSharedArrayBuffer(O)) === null) {
|
||||||
|
return callFunction(
|
||||||
|
CallSharedArrayBufferMethodIfWrapped,
|
||||||
|
this,
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
"SharedArrayBufferSlice"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 4.
|
||||||
|
var len = SharedArrayBufferByteLength(O);
|
||||||
|
|
||||||
|
// Step 5.
|
||||||
|
var relativeStart = ToInteger(start);
|
||||||
|
|
||||||
|
// Step 6.
|
||||||
|
var first =
|
||||||
|
relativeStart < 0
|
||||||
|
? std_Math_max(len + relativeStart, 0)
|
||||||
|
: std_Math_min(relativeStart, len);
|
||||||
|
|
||||||
|
// Step 7.
|
||||||
|
var relativeEnd = end === undefined ? len : ToInteger(end);
|
||||||
|
|
||||||
|
// Step 8.
|
||||||
|
var final =
|
||||||
|
relativeEnd < 0
|
||||||
|
? std_Math_max(len + relativeEnd, 0)
|
||||||
|
: std_Math_min(relativeEnd, len);
|
||||||
|
|
||||||
|
// Step 9.
|
||||||
|
var newLen = std_Math_max(final - first, 0);
|
||||||
|
|
||||||
|
// Step 10
|
||||||
|
var ctor = SpeciesConstructor(O, GetBuiltinConstructor("SharedArrayBuffer"));
|
||||||
|
|
||||||
|
// Step 11.
|
||||||
|
var new_ = constructContentFunction(ctor, ctor, newLen);
|
||||||
|
|
||||||
|
// Steps 12-13.
|
||||||
|
var isWrapped = false;
|
||||||
|
var newObj;
|
||||||
|
if ((newObj = GuardToSharedArrayBuffer(new_)) === null) {
|
||||||
|
if (!IsWrappedSharedArrayBuffer(new_)) {
|
||||||
|
ThrowTypeError(JSMSG_NON_SHARED_ARRAY_BUFFER_RETURNED);
|
||||||
|
}
|
||||||
|
isWrapped = true;
|
||||||
|
newObj = new_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 14.
|
||||||
|
if (newObj === O || SharedArrayBuffersMemorySame(newObj, O)) {
|
||||||
|
ThrowTypeError(JSMSG_SAME_SHARED_ARRAY_BUFFER_RETURNED);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 15.
|
||||||
|
var actualLen = PossiblyWrappedSharedArrayBufferByteLength(newObj);
|
||||||
|
if (actualLen < newLen) {
|
||||||
|
ThrowTypeError(JSMSG_SHORT_SHARED_ARRAY_BUFFER_RETURNED, newLen, actualLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Steps 16-18.
|
||||||
|
SharedArrayBufferCopyData(newObj, 0, O, first, newLen, isWrapped);
|
||||||
|
|
||||||
|
// Step 19.
|
||||||
|
return newObj;
|
||||||
|
}
|
||||||
|
|
||||||
// https://github.com/tc39/proposal-change-array-by-copy
|
// https://github.com/tc39/proposal-change-array-by-copy
|
||||||
function TypedArrayCreateSameType(exemplar, length) {
|
function TypedArrayCreateSameType(exemplar, length) {
|
||||||
// Step 1. Assert: exemplar is an Object that has [[TypedArrayName]] and [[ContentType]] internal slots.
|
// Step 1. Assert: exemplar is an Object that has [[TypedArrayName]] and [[ContentType]] internal slots.
|
||||||
|
|||||||
@@ -737,8 +737,7 @@ bool ParserAtomsTable::isExtendedUnclonedSelfHostedFunctionName(
|
|||||||
case WellKnownAtomId::dollar_ArraySpecies_:
|
case WellKnownAtomId::dollar_ArraySpecies_:
|
||||||
case WellKnownAtomId::dollar_ArrayValues_:
|
case WellKnownAtomId::dollar_ArrayValues_:
|
||||||
case WellKnownAtomId::dollar_RegExpFlagsGetter_:
|
case WellKnownAtomId::dollar_RegExpFlagsGetter_:
|
||||||
case WellKnownAtomId::dollar_RegExpToString_:
|
case WellKnownAtomId::dollar_RegExpToString_: {
|
||||||
case WellKnownAtomId::dollar_SharedArrayBufferSpecies_: {
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
const auto& info = GetWellKnownAtomInfo(index.toWellKnownAtomId());
|
const auto& info = GetWellKnownAtomInfo(index.toWellKnownAtomId());
|
||||||
MOZ_ASSERT(info.content[0] ==
|
MOZ_ASSERT(info.content[0] ==
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
function test() {
|
|
||||||
// Mutating ArrayBuffer.prototype.constructor pops the fuse. A no-op change is fine.
|
|
||||||
newGlobal().evaluate(`
|
|
||||||
assertEq(getFuseState().OptimizeArrayBufferSpeciesFuse.intact, true);
|
|
||||||
let p = ArrayBuffer.prototype.constructor;
|
|
||||||
ArrayBuffer.prototype.constructor = p;
|
|
||||||
assertEq(getFuseState().OptimizeArrayBufferSpeciesFuse.intact, true);
|
|
||||||
ArrayBuffer.prototype.constructor = Object;
|
|
||||||
assertEq(getFuseState().OptimizeArrayBufferSpeciesFuse.intact, false);
|
|
||||||
`);
|
|
||||||
|
|
||||||
// Mutating ArrayBuffer[Symbol.species] pops the fuse.
|
|
||||||
newGlobal().evaluate(`
|
|
||||||
assertEq(getFuseState().OptimizeArrayBufferSpeciesFuse.intact, true);
|
|
||||||
delete ArrayBuffer[Symbol.species];
|
|
||||||
assertEq(getFuseState().OptimizeArrayBufferSpeciesFuse.intact, false);
|
|
||||||
`);
|
|
||||||
}
|
|
||||||
test();
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
// Test for array buffer species fuse with multiple realms.
|
|
||||||
function test() {
|
|
||||||
var g = newGlobal();
|
|
||||||
var arr = g.evaluate(`new ArrayBuffer(4)`);
|
|
||||||
var count = 0;
|
|
||||||
Object.defineProperty(g.ArrayBuffer.prototype, "constructor", {get: function() {
|
|
||||||
count++;
|
|
||||||
return ArrayBuffer;
|
|
||||||
}});
|
|
||||||
for (var i = 0; i < 20; i++) {
|
|
||||||
assertEq(ArrayBuffer.prototype.slice.call(arr).byteLength, 4);
|
|
||||||
}
|
|
||||||
assertEq(count, 20);
|
|
||||||
assertEq(getFuseState().OptimizeArrayBufferSpeciesFuse.intact, true);
|
|
||||||
assertEq(g.getFuseState().OptimizeArrayBufferSpeciesFuse.intact, false);
|
|
||||||
}
|
|
||||||
test();
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
function test() {
|
|
||||||
// Mutating SharedArrayBuffer.prototype.constructor pops the fuse. A no-op change is fine.
|
|
||||||
newGlobal().evaluate(`
|
|
||||||
assertEq(getFuseState().OptimizeSharedArrayBufferSpeciesFuse.intact, true);
|
|
||||||
let p = SharedArrayBuffer.prototype.constructor;
|
|
||||||
SharedArrayBuffer.prototype.constructor = p;
|
|
||||||
assertEq(getFuseState().OptimizeSharedArrayBufferSpeciesFuse.intact, true);
|
|
||||||
SharedArrayBuffer.prototype.constructor = Object;
|
|
||||||
assertEq(getFuseState().OptimizeSharedArrayBufferSpeciesFuse.intact, false);
|
|
||||||
`);
|
|
||||||
|
|
||||||
// Mutating SharedArrayBuffer[Symbol.species] pops the fuse.
|
|
||||||
newGlobal().evaluate(`
|
|
||||||
assertEq(getFuseState().OptimizeSharedArrayBufferSpeciesFuse.intact, true);
|
|
||||||
delete SharedArrayBuffer[Symbol.species];
|
|
||||||
assertEq(getFuseState().OptimizeSharedArrayBufferSpeciesFuse.intact, false);
|
|
||||||
`);
|
|
||||||
}
|
|
||||||
test();
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
// Test for shared array buffer species fuse with multiple realms.
|
|
||||||
function test() {
|
|
||||||
var g = newGlobal();
|
|
||||||
var arr = g.evaluate(`new SharedArrayBuffer(4)`);
|
|
||||||
var count = 0;
|
|
||||||
Object.defineProperty(g.SharedArrayBuffer.prototype, "constructor", {get: function() {
|
|
||||||
count++;
|
|
||||||
return SharedArrayBuffer;
|
|
||||||
}});
|
|
||||||
for (var i = 0; i < 20; i++) {
|
|
||||||
assertEq(SharedArrayBuffer.prototype.slice.call(arr).byteLength, 4);
|
|
||||||
}
|
|
||||||
assertEq(count, 20);
|
|
||||||
assertEq(getFuseState().OptimizeSharedArrayBufferSpeciesFuse.intact, true);
|
|
||||||
assertEq(g.getFuseState().OptimizeSharedArrayBufferSpeciesFuse.intact, false);
|
|
||||||
}
|
|
||||||
test();
|
|
||||||
20
js/src/jit-test/tests/ion/testArrayBufferByteLength.js
Normal file
20
js/src/jit-test/tests/ion/testArrayBufferByteLength.js
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
// |jit-test| --ion-warmup-threshold=50
|
||||||
|
|
||||||
|
var ArrayBufferByteLength = getSelfHostedValue("ArrayBufferByteLength");
|
||||||
|
|
||||||
|
function testBasic() {
|
||||||
|
var arr = [1, 2, 3];
|
||||||
|
var tarr = new Int32Array(arr);
|
||||||
|
var abuf = tarr.buffer;
|
||||||
|
|
||||||
|
var arrLength = arr.length;
|
||||||
|
var bytesPerElement = Int32Array.BYTES_PER_ELEMENT;
|
||||||
|
|
||||||
|
var f = function() {
|
||||||
|
assertEq(ArrayBufferByteLength(abuf), arrLength * bytesPerElement);
|
||||||
|
};
|
||||||
|
do {
|
||||||
|
f();
|
||||||
|
} while (!inIon());
|
||||||
|
}
|
||||||
|
testBasic();
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
// |jit-test| --ion-warmup-threshold=50
|
||||||
|
|
||||||
|
var PossiblyWrappedArrayBufferByteLength = getSelfHostedValue("PossiblyWrappedArrayBufferByteLength");
|
||||||
|
|
||||||
|
function testBasic() {
|
||||||
|
var arr = [1, 2, 3];
|
||||||
|
var tarr = new Int32Array(arr);
|
||||||
|
var abuf = tarr.buffer;
|
||||||
|
|
||||||
|
var arrLength = arr.length;
|
||||||
|
var bytesPerElement = Int32Array.BYTES_PER_ELEMENT;
|
||||||
|
|
||||||
|
var f = function() {
|
||||||
|
assertEq(PossiblyWrappedArrayBufferByteLength(abuf), arrLength * bytesPerElement);
|
||||||
|
};
|
||||||
|
do {
|
||||||
|
f();
|
||||||
|
} while (!inIon());
|
||||||
|
}
|
||||||
|
testBasic();
|
||||||
|
|
||||||
|
function testWrapped() {
|
||||||
|
var g = newGlobal();
|
||||||
|
g.eval(`
|
||||||
|
var arr = [1, 2, 3];
|
||||||
|
var tarr = new Int32Array(arr);
|
||||||
|
var abuf = tarr.buffer;
|
||||||
|
`);
|
||||||
|
|
||||||
|
var abuf = g.abuf;
|
||||||
|
var arrLength = g.arr.length;
|
||||||
|
var bytesPerElement = g.Int32Array.BYTES_PER_ELEMENT;
|
||||||
|
|
||||||
|
var f = function() {
|
||||||
|
assertEq(PossiblyWrappedArrayBufferByteLength(abuf), arrLength * bytesPerElement);
|
||||||
|
};
|
||||||
|
do {
|
||||||
|
f();
|
||||||
|
} while (!inIon());
|
||||||
|
}
|
||||||
|
testWrapped();
|
||||||
@@ -11,6 +11,7 @@ const dvSmall = new DataView(bufferSmall);
|
|||||||
const dvLargeOffset = new DataView(bufferLarge, 5 * gb);
|
const dvLargeOffset = new DataView(bufferLarge, 5 * gb);
|
||||||
const dvLargeLength = new DataView(bufferLarge);
|
const dvLargeLength = new DataView(bufferLarge);
|
||||||
|
|
||||||
|
const ArrayBufferByteLength = getSelfHostedValue("ArrayBufferByteLength");
|
||||||
const TypedArrayByteOffset = getSelfHostedValue("TypedArrayByteOffset");
|
const TypedArrayByteOffset = getSelfHostedValue("TypedArrayByteOffset");
|
||||||
const TypedArrayLength = getSelfHostedValue("TypedArrayLength");
|
const TypedArrayLength = getSelfHostedValue("TypedArrayLength");
|
||||||
|
|
||||||
@@ -18,6 +19,7 @@ function testBufferByteLengthInt32() {
|
|||||||
var arr = [bufferLarge, bufferSmall];
|
var arr = [bufferLarge, bufferSmall];
|
||||||
for (var i = 0; i < 2000; i++) {
|
for (var i = 0; i < 2000; i++) {
|
||||||
var idx = +(i < 1900); // First 1 then 0.
|
var idx = +(i < 1900); // First 1 then 0.
|
||||||
|
assertEq(ArrayBufferByteLength(arr[idx]), idx === 0 ? 6 * gb : 8);
|
||||||
assertEq(arr[idx].byteLength, idx === 0 ? 6 * gb : 8);
|
assertEq(arr[idx].byteLength, idx === 0 ? 6 * gb : 8);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11122,6 +11122,45 @@ AttachDecision InlinableNativeIRGenerator::tryAttachTypedArrayLength(
|
|||||||
return AttachDecision::Attach;
|
return AttachDecision::Attach;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AttachDecision InlinableNativeIRGenerator::tryAttachArrayBufferByteLength(
|
||||||
|
bool isPossiblyWrapped) {
|
||||||
|
// Self-hosted code calls this with a single, possibly wrapped,
|
||||||
|
// ArrayBufferObject argument.
|
||||||
|
MOZ_ASSERT(args_.length() == 1);
|
||||||
|
MOZ_ASSERT(args_[0].isObject());
|
||||||
|
|
||||||
|
// Only optimize when the object isn't a wrapper.
|
||||||
|
if (isPossiblyWrapped && IsWrapper(&args_[0].toObject())) {
|
||||||
|
return AttachDecision::NoAction;
|
||||||
|
}
|
||||||
|
|
||||||
|
MOZ_ASSERT(args_[0].toObject().is<ArrayBufferObject>());
|
||||||
|
|
||||||
|
auto* buffer = &args_[0].toObject().as<ArrayBufferObject>();
|
||||||
|
|
||||||
|
// Initialize the input operand.
|
||||||
|
initializeInputOperand();
|
||||||
|
|
||||||
|
// Note: we don't need to call emitNativeCalleeGuard for intrinsics.
|
||||||
|
|
||||||
|
ValOperandId argId = loadArgumentIntrinsic(ArgumentKind::Arg0);
|
||||||
|
ObjOperandId objArgId = writer.guardToObject(argId);
|
||||||
|
|
||||||
|
if (isPossiblyWrapped) {
|
||||||
|
writer.guardIsNotProxy(objArgId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buffer->byteLength() <= INT32_MAX) {
|
||||||
|
writer.loadArrayBufferByteLengthInt32Result(objArgId);
|
||||||
|
} else {
|
||||||
|
writer.loadArrayBufferByteLengthDoubleResult(objArgId);
|
||||||
|
}
|
||||||
|
writer.returnFromIC();
|
||||||
|
|
||||||
|
trackAttached("ArrayBufferByteLength");
|
||||||
|
return AttachDecision::Attach;
|
||||||
|
}
|
||||||
|
|
||||||
AttachDecision InlinableNativeIRGenerator::tryAttachIsConstructing() {
|
AttachDecision InlinableNativeIRGenerator::tryAttachIsConstructing() {
|
||||||
// Self-hosted code calls this with no arguments in function scripts.
|
// Self-hosted code calls this with no arguments in function scripts.
|
||||||
MOZ_ASSERT(args_.length() == 0);
|
MOZ_ASSERT(args_.length() == 0);
|
||||||
@@ -12467,6 +12506,10 @@ AttachDecision InlinableNativeIRGenerator::tryAttachStub() {
|
|||||||
// ArrayBuffer intrinsics.
|
// ArrayBuffer intrinsics.
|
||||||
case InlinableNative::IntrinsicGuardToArrayBuffer:
|
case InlinableNative::IntrinsicGuardToArrayBuffer:
|
||||||
return tryAttachGuardToArrayBuffer();
|
return tryAttachGuardToArrayBuffer();
|
||||||
|
case InlinableNative::IntrinsicArrayBufferByteLength:
|
||||||
|
return tryAttachArrayBufferByteLength(/* isPossiblyWrapped = */ false);
|
||||||
|
case InlinableNative::IntrinsicPossiblyWrappedArrayBufferByteLength:
|
||||||
|
return tryAttachArrayBufferByteLength(/* isPossiblyWrapped = */ true);
|
||||||
|
|
||||||
// SharedArrayBuffer intrinsics.
|
// SharedArrayBuffer intrinsics.
|
||||||
case InlinableNative::IntrinsicGuardToSharedArrayBuffer:
|
case InlinableNative::IntrinsicGuardToSharedArrayBuffer:
|
||||||
|
|||||||
@@ -756,6 +756,7 @@ class MOZ_RAII InlinableNativeIRGenerator {
|
|||||||
AttachDecision tryAttachTypedArrayElementSize();
|
AttachDecision tryAttachTypedArrayElementSize();
|
||||||
AttachDecision tryAttachTypedArrayLength(bool isPossiblyWrapped,
|
AttachDecision tryAttachTypedArrayLength(bool isPossiblyWrapped,
|
||||||
bool allowOutOfBounds);
|
bool allowOutOfBounds);
|
||||||
|
AttachDecision tryAttachArrayBufferByteLength(bool isPossiblyWrapped);
|
||||||
AttachDecision tryAttachIsConstructing();
|
AttachDecision tryAttachIsConstructing();
|
||||||
AttachDecision tryAttachGetNextMapSetEntryForIterator(bool isMap);
|
AttachDecision tryAttachGetNextMapSetEntryForIterator(bool isMap);
|
||||||
AttachDecision tryAttachNewArrayIterator();
|
AttachDecision tryAttachNewArrayIterator();
|
||||||
|
|||||||
@@ -238,6 +238,8 @@ bool js::jit::CanInlineNativeCrossRealm(InlinableNative native) {
|
|||||||
case InlinableNative::IntrinsicGuardToSetObject:
|
case InlinableNative::IntrinsicGuardToSetObject:
|
||||||
case InlinableNative::IntrinsicGetNextSetEntryForIterator:
|
case InlinableNative::IntrinsicGetNextSetEntryForIterator:
|
||||||
case InlinableNative::IntrinsicGuardToArrayBuffer:
|
case InlinableNative::IntrinsicGuardToArrayBuffer:
|
||||||
|
case InlinableNative::IntrinsicArrayBufferByteLength:
|
||||||
|
case InlinableNative::IntrinsicPossiblyWrappedArrayBufferByteLength:
|
||||||
case InlinableNative::IntrinsicGuardToSharedArrayBuffer:
|
case InlinableNative::IntrinsicGuardToSharedArrayBuffer:
|
||||||
case InlinableNative::IntrinsicIsTypedArrayConstructor:
|
case InlinableNative::IntrinsicIsTypedArrayConstructor:
|
||||||
case InlinableNative::IntrinsicIsTypedArray:
|
case InlinableNative::IntrinsicIsTypedArray:
|
||||||
|
|||||||
@@ -243,6 +243,8 @@
|
|||||||
_(IntrinsicArrayIteratorPrototypeOptimizable) \
|
_(IntrinsicArrayIteratorPrototypeOptimizable) \
|
||||||
\
|
\
|
||||||
_(IntrinsicGuardToArrayBuffer) \
|
_(IntrinsicGuardToArrayBuffer) \
|
||||||
|
_(IntrinsicArrayBufferByteLength) \
|
||||||
|
_(IntrinsicPossiblyWrappedArrayBufferByteLength) \
|
||||||
\
|
\
|
||||||
_(IntrinsicGuardToSharedArrayBuffer) \
|
_(IntrinsicGuardToSharedArrayBuffer) \
|
||||||
\
|
\
|
||||||
|
|||||||
@@ -2205,39 +2205,6 @@ bool js::ToIndexSlow(JSContext* cx, JS::HandleValue v,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert |value| to an integer and clamp it to a valid integer index within
|
|
||||||
* the range `[0..length]`.
|
|
||||||
*/
|
|
||||||
template <typename ArrayLength>
|
|
||||||
bool js::ToIntegerIndexSlow(JSContext* cx, Handle<Value> value,
|
|
||||||
ArrayLength length, ArrayLength* result) {
|
|
||||||
MOZ_ASSERT(!value.isInt32());
|
|
||||||
|
|
||||||
double relative;
|
|
||||||
if (!ToInteger(cx, value, &relative)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (relative >= 0) {
|
|
||||||
*result = ArrayLength(std::min(relative, double(length)));
|
|
||||||
} else {
|
|
||||||
*result = ArrayLength(std::max(relative + double(length), 0.0));
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static_assert(std::is_same_v<size_t, uint32_t> ||
|
|
||||||
std::is_same_v<size_t, uint64_t>,
|
|
||||||
"If this assertion fails, add the corresponding unsigned int "
|
|
||||||
"type for size_t to the explicit instantiations below");
|
|
||||||
|
|
||||||
template bool js::ToIntegerIndexSlow<uint32_t>(JSContext*, Handle<Value>,
|
|
||||||
uint32_t, uint32_t*);
|
|
||||||
|
|
||||||
template bool js::ToIntegerIndexSlow<uint64_t>(JSContext*, Handle<Value>,
|
|
||||||
uint64_t, uint64_t*);
|
|
||||||
|
|
||||||
template <typename CharT>
|
template <typename CharT>
|
||||||
double js_strtod(const CharT* begin, const CharT* end, const CharT** dEnd) {
|
double js_strtod(const CharT* begin, const CharT* end, const CharT** dEnd) {
|
||||||
const CharT* s = SkipSpace(begin, end);
|
const CharT* s = SkipSpace(begin, end);
|
||||||
|
|||||||
@@ -404,40 +404,6 @@ static MOZ_ALWAYS_INLINE bool IsDefinitelyIndex(const Value& v,
|
|||||||
return ToIndex(cx, v, JSMSG_BAD_INDEX, index);
|
return ToIndex(cx, v, JSMSG_BAD_INDEX, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert |value| to an integer and clamp it to a valid integer index within
|
|
||||||
* the range `[0..length]`.
|
|
||||||
*/
|
|
||||||
template <typename ArrayLength>
|
|
||||||
[[nodiscard]] extern bool ToIntegerIndexSlow(JSContext* cx, Handle<Value> value,
|
|
||||||
ArrayLength length,
|
|
||||||
ArrayLength* result);
|
|
||||||
|
|
||||||
template <typename ArrayLength>
|
|
||||||
[[nodiscard]] static inline bool ToIntegerIndex(JSContext* cx,
|
|
||||||
Handle<Value> value,
|
|
||||||
ArrayLength length,
|
|
||||||
ArrayLength* result) {
|
|
||||||
static_assert(std::is_unsigned_v<ArrayLength>);
|
|
||||||
|
|
||||||
// Optimize for the common case when |value| is an int32 to avoid unnecessary
|
|
||||||
// floating point computations.
|
|
||||||
if (value.isInt32()) {
|
|
||||||
int32_t relative = value.toInt32();
|
|
||||||
|
|
||||||
if (relative >= 0) {
|
|
||||||
*result = std::min(ArrayLength(relative), length);
|
|
||||||
} else if (mozilla::Abs(relative) <= length) {
|
|
||||||
*result = length - mozilla::Abs(relative);
|
|
||||||
} else {
|
|
||||||
*result = 0;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ToIntegerIndexSlow(cx, value, length, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
} /* namespace js */
|
} /* namespace js */
|
||||||
|
|
||||||
#endif /* jsnum_h */
|
#endif /* jsnum_h */
|
||||||
|
|||||||
@@ -43,10 +43,8 @@
|
|||||||
#include "js/Wrapper.h"
|
#include "js/Wrapper.h"
|
||||||
#include "util/WindowsWrapper.h"
|
#include "util/WindowsWrapper.h"
|
||||||
#include "vm/GlobalObject.h"
|
#include "vm/GlobalObject.h"
|
||||||
#include "vm/Interpreter.h"
|
|
||||||
#include "vm/JSContext.h"
|
#include "vm/JSContext.h"
|
||||||
#include "vm/JSObject.h"
|
#include "vm/JSObject.h"
|
||||||
#include "vm/SelfHosting.h"
|
|
||||||
#include "vm/SharedArrayObject.h"
|
#include "vm/SharedArrayObject.h"
|
||||||
#include "vm/Warnings.h" // js::WarnNumberASCII
|
#include "vm/Warnings.h" // js::WarnNumberASCII
|
||||||
#include "wasm/WasmConstants.h"
|
#include "wasm/WasmConstants.h"
|
||||||
@@ -331,7 +329,7 @@ static const JSPropertySpec arraybuffer_properties[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static const JSFunctionSpec arraybuffer_proto_functions[] = {
|
static const JSFunctionSpec arraybuffer_proto_functions[] = {
|
||||||
JS_FN("slice", ArrayBufferObject::slice, 2, 0),
|
JS_SELF_HOSTED_FN("slice", "ArrayBufferSlice", 2, 0),
|
||||||
JS_FN("resize", ArrayBufferObject::resize, 1, 0),
|
JS_FN("resize", ArrayBufferObject::resize, 1, 0),
|
||||||
JS_FN("transfer", ArrayBufferObject::transfer, 0, 0),
|
JS_FN("transfer", ArrayBufferObject::transfer, 0, 0),
|
||||||
JS_FN("transferToFixedLength", ArrayBufferObject::transferToFixedLength, 0,
|
JS_FN("transferToFixedLength", ArrayBufferObject::transferToFixedLength, 0,
|
||||||
@@ -361,7 +359,6 @@ static const ClassSpec ArrayBufferObjectClassSpec = {
|
|||||||
arraybuffer_properties,
|
arraybuffer_properties,
|
||||||
arraybuffer_proto_functions,
|
arraybuffer_proto_functions,
|
||||||
arraybuffer_proto_properties,
|
arraybuffer_proto_properties,
|
||||||
GenericFinishInit<WhichHasFuseProperty::ProtoAndCtor>,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const ClassExtension FixedLengthArrayBufferObjectClassExtension = {
|
static const ClassExtension FixedLengthArrayBufferObjectClassExtension = {
|
||||||
@@ -729,190 +726,6 @@ bool ArrayBufferObject::resize(JSContext* cx, unsigned argc, Value* vp) {
|
|||||||
return CallNonGenericMethod<IsResizableArrayBuffer, resizeImpl>(cx, args);
|
return CallNonGenericMethod<IsResizableArrayBuffer, resizeImpl>(cx, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool IsArrayBufferSpecies(JSContext* cx, JSFunction* species) {
|
|
||||||
return IsSelfHostedFunctionWithName(species,
|
|
||||||
cx->names().dollar_ArrayBufferSpecies_);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool HasBuiltinArrayBufferSpecies(ArrayBufferObject* obj,
|
|
||||||
JSContext* cx) {
|
|
||||||
// Ensure `ArrayBuffer.prototype.constructor` and `ArrayBuffer[@@species]`
|
|
||||||
// haven't been mutated.
|
|
||||||
if (!cx->realm()->realmFuses.optimizeArrayBufferSpeciesFuse.intact()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure |obj|'s prototype is the actual ArrayBuffer.prototype.
|
|
||||||
auto* proto = cx->global()->maybeGetPrototype(JSProto_ArrayBuffer);
|
|
||||||
if (!proto || obj->staticPrototype() != proto) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fail if |obj| has an own `constructor` property.
|
|
||||||
if (obj->containsPure(NameToId(cx->names().constructor))) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ArrayBuffer.prototype.slice ( start, end )
|
|
||||||
*
|
|
||||||
* https://tc39.es/ecma262/#sec-arraybuffer.prototype.slice
|
|
||||||
*/
|
|
||||||
bool ArrayBufferObject::sliceImpl(JSContext* cx, const CallArgs& args) {
|
|
||||||
MOZ_ASSERT(IsArrayBuffer(args.thisv()));
|
|
||||||
|
|
||||||
Rooted<ArrayBufferObject*> obj(
|
|
||||||
cx, &args.thisv().toObject().as<ArrayBufferObject>());
|
|
||||||
|
|
||||||
// Step 4.
|
|
||||||
if (obj->isDetached()) {
|
|
||||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
|
|
||||||
JSMSG_TYPED_ARRAY_DETACHED);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 5.
|
|
||||||
size_t len = obj->byteLength();
|
|
||||||
|
|
||||||
// Steps 6-9.
|
|
||||||
size_t first = 0;
|
|
||||||
if (args.hasDefined(0)) {
|
|
||||||
if (!ToIntegerIndex(cx, args[0], len, &first)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Steps 10-13.
|
|
||||||
size_t final_ = len;
|
|
||||||
if (args.hasDefined(1)) {
|
|
||||||
if (!ToIntegerIndex(cx, args[1], len, &final_)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 14.
|
|
||||||
size_t newLen = final_ >= first ? final_ - first : 0;
|
|
||||||
MOZ_ASSERT(newLen <= ArrayBufferObject::ByteLengthLimit);
|
|
||||||
|
|
||||||
// Steps 15-21.
|
|
||||||
Rooted<JSObject*> resultObj(cx);
|
|
||||||
ArrayBufferObject* unwrappedResult = nullptr;
|
|
||||||
if (HasBuiltinArrayBufferSpecies(obj, cx)) {
|
|
||||||
// Steps 15-16.
|
|
||||||
unwrappedResult = createZeroed(cx, newLen);
|
|
||||||
if (!unwrappedResult) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
resultObj.set(unwrappedResult);
|
|
||||||
|
|
||||||
// Steps 17-18. (Not applicable)
|
|
||||||
|
|
||||||
// Step 19.
|
|
||||||
MOZ_ASSERT(!unwrappedResult->isDetached());
|
|
||||||
|
|
||||||
// Step 20.
|
|
||||||
MOZ_ASSERT(unwrappedResult != obj);
|
|
||||||
|
|
||||||
// Step 21.
|
|
||||||
MOZ_ASSERT(unwrappedResult->byteLength() == newLen);
|
|
||||||
} else {
|
|
||||||
// Step 15.
|
|
||||||
Rooted<JSObject*> ctor(cx, SpeciesConstructor(cx, obj, JSProto_ArrayBuffer,
|
|
||||||
IsArrayBufferSpecies));
|
|
||||||
if (!ctor) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 16.
|
|
||||||
{
|
|
||||||
FixedConstructArgs<1> cargs(cx);
|
|
||||||
cargs[0].setNumber(newLen);
|
|
||||||
|
|
||||||
Rooted<Value> ctorVal(cx, ObjectValue(*ctor));
|
|
||||||
if (!Construct(cx, ctorVal, cargs, ctorVal, &resultObj)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Steps 17-18.
|
|
||||||
unwrappedResult = resultObj->maybeUnwrapIf<ArrayBufferObject>();
|
|
||||||
if (!unwrappedResult) {
|
|
||||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
|
|
||||||
JSMSG_NON_ARRAY_BUFFER_RETURNED);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 19.
|
|
||||||
if (unwrappedResult->isDetached()) {
|
|
||||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
|
|
||||||
JSMSG_TYPED_ARRAY_DETACHED);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 20.
|
|
||||||
if (unwrappedResult == obj) {
|
|
||||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
|
|
||||||
JSMSG_SAME_ARRAY_BUFFER_RETURNED);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 21.
|
|
||||||
size_t resultByteLength = unwrappedResult->byteLength();
|
|
||||||
if (resultByteLength < newLen) {
|
|
||||||
ToCStringBuf resultLenCbuf;
|
|
||||||
const char* resultLenStr =
|
|
||||||
NumberToCString(&resultLenCbuf, double(resultByteLength));
|
|
||||||
|
|
||||||
ToCStringBuf newLenCbuf;
|
|
||||||
const char* newLenStr = NumberToCString(&newLenCbuf, double(newLen));
|
|
||||||
|
|
||||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
|
|
||||||
JSMSG_SHORT_ARRAY_BUFFER_RETURNED, newLenStr,
|
|
||||||
resultLenStr);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Steps 22-23.
|
|
||||||
if (obj->isDetached()) {
|
|
||||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
|
|
||||||
JSMSG_TYPED_ARRAY_DETACHED);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 26.
|
|
||||||
//
|
|
||||||
// Reacquire the length in case the buffer has been resized.
|
|
||||||
size_t currentLen = obj->byteLength();
|
|
||||||
|
|
||||||
// Steps 24-25 and 27.
|
|
||||||
if (first < currentLen) {
|
|
||||||
// Step 27.a.
|
|
||||||
size_t count = std::min(newLen, currentLen - first);
|
|
||||||
|
|
||||||
// Steps 24-25 and 27.b.
|
|
||||||
ArrayBufferObject::copyData(unwrappedResult, 0, obj, first, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 28.
|
|
||||||
args.rval().setObject(*resultObj);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ArrayBuffer.prototype.slice ( start, end )
|
|
||||||
*
|
|
||||||
* https://tc39.es/ecma262/#sec-arraybuffer.prototype.slice
|
|
||||||
*/
|
|
||||||
bool ArrayBufferObject::slice(JSContext* cx, unsigned argc, Value* vp) {
|
|
||||||
// Steps 1-3.
|
|
||||||
CallArgs args = CallArgsFromVp(argc, vp);
|
|
||||||
return CallNonGenericMethod<IsArrayBuffer, sliceImpl>(cx, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ArrayBuffer.isView(obj); ES6 (Dec 2013 draft) 24.1.3.1
|
* ArrayBuffer.isView(obj); ES6 (Dec 2013 draft) 24.1.3.1
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -183,7 +183,6 @@ class ArrayBufferObject : public ArrayBufferObjectMaybeShared {
|
|||||||
static bool maxByteLengthGetterImpl(JSContext* cx, const CallArgs& args);
|
static bool maxByteLengthGetterImpl(JSContext* cx, const CallArgs& args);
|
||||||
static bool resizableGetterImpl(JSContext* cx, const CallArgs& args);
|
static bool resizableGetterImpl(JSContext* cx, const CallArgs& args);
|
||||||
static bool detachedGetterImpl(JSContext* cx, const CallArgs& args);
|
static bool detachedGetterImpl(JSContext* cx, const CallArgs& args);
|
||||||
static bool sliceImpl(JSContext* cx, const CallArgs& args);
|
|
||||||
static bool resizeImpl(JSContext* cx, const CallArgs& args);
|
static bool resizeImpl(JSContext* cx, const CallArgs& args);
|
||||||
static bool transferImpl(JSContext* cx, const CallArgs& args);
|
static bool transferImpl(JSContext* cx, const CallArgs& args);
|
||||||
static bool transferToFixedLengthImpl(JSContext* cx, const CallArgs& args);
|
static bool transferToFixedLengthImpl(JSContext* cx, const CallArgs& args);
|
||||||
@@ -423,8 +422,6 @@ class ArrayBufferObject : public ArrayBufferObjectMaybeShared {
|
|||||||
|
|
||||||
static bool fun_isView(JSContext* cx, unsigned argc, Value* vp);
|
static bool fun_isView(JSContext* cx, unsigned argc, Value* vp);
|
||||||
|
|
||||||
static bool slice(JSContext* cx, unsigned argc, Value* vp);
|
|
||||||
|
|
||||||
static bool resize(JSContext* cx, unsigned argc, Value* vp);
|
static bool resize(JSContext* cx, unsigned argc, Value* vp);
|
||||||
|
|
||||||
static bool transfer(JSContext* cx, unsigned argc, Value* vp);
|
static bool transfer(JSContext* cx, unsigned argc, Value* vp);
|
||||||
|
|||||||
@@ -17,6 +17,10 @@ static JSProtoKey ToProtoKey(BuiltinObjectKind kind) {
|
|||||||
switch (kind) {
|
switch (kind) {
|
||||||
case BuiltinObjectKind::Array:
|
case BuiltinObjectKind::Array:
|
||||||
return JSProto_Array;
|
return JSProto_Array;
|
||||||
|
case BuiltinObjectKind::ArrayBuffer:
|
||||||
|
return JSProto_ArrayBuffer;
|
||||||
|
case BuiltinObjectKind::Int32Array:
|
||||||
|
return JSProto_Int32Array;
|
||||||
case BuiltinObjectKind::ListFormat:
|
case BuiltinObjectKind::ListFormat:
|
||||||
return JSProto_ListFormat;
|
return JSProto_ListFormat;
|
||||||
case BuiltinObjectKind::Map:
|
case BuiltinObjectKind::Map:
|
||||||
@@ -27,6 +31,8 @@ static JSProtoKey ToProtoKey(BuiltinObjectKind kind) {
|
|||||||
return JSProto_RegExp;
|
return JSProto_RegExp;
|
||||||
case BuiltinObjectKind::Set:
|
case BuiltinObjectKind::Set:
|
||||||
return JSProto_Set;
|
return JSProto_Set;
|
||||||
|
case BuiltinObjectKind::SharedArrayBuffer:
|
||||||
|
return JSProto_SharedArrayBuffer;
|
||||||
case BuiltinObjectKind::Symbol:
|
case BuiltinObjectKind::Symbol:
|
||||||
return JSProto_Symbol;
|
return JSProto_Symbol;
|
||||||
|
|
||||||
@@ -34,6 +40,12 @@ static JSProtoKey ToProtoKey(BuiltinObjectKind kind) {
|
|||||||
return JSProto_Function;
|
return JSProto_Function;
|
||||||
case BuiltinObjectKind::IteratorPrototype:
|
case BuiltinObjectKind::IteratorPrototype:
|
||||||
return JSProto_Iterator;
|
return JSProto_Iterator;
|
||||||
|
case BuiltinObjectKind::ObjectPrototype:
|
||||||
|
return JSProto_Object;
|
||||||
|
case BuiltinObjectKind::RegExpPrototype:
|
||||||
|
return JSProto_RegExp;
|
||||||
|
case BuiltinObjectKind::StringPrototype:
|
||||||
|
return JSProto_String;
|
||||||
|
|
||||||
case BuiltinObjectKind::DateTimeFormatPrototype:
|
case BuiltinObjectKind::DateTimeFormatPrototype:
|
||||||
return JSProto_DateTimeFormat;
|
return JSProto_DateTimeFormat;
|
||||||
@@ -49,16 +61,22 @@ static JSProtoKey ToProtoKey(BuiltinObjectKind kind) {
|
|||||||
static bool IsPrototype(BuiltinObjectKind kind) {
|
static bool IsPrototype(BuiltinObjectKind kind) {
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
case BuiltinObjectKind::Array:
|
case BuiltinObjectKind::Array:
|
||||||
|
case BuiltinObjectKind::ArrayBuffer:
|
||||||
|
case BuiltinObjectKind::Int32Array:
|
||||||
case BuiltinObjectKind::ListFormat:
|
case BuiltinObjectKind::ListFormat:
|
||||||
case BuiltinObjectKind::Map:
|
case BuiltinObjectKind::Map:
|
||||||
case BuiltinObjectKind::Promise:
|
case BuiltinObjectKind::Promise:
|
||||||
case BuiltinObjectKind::RegExp:
|
case BuiltinObjectKind::RegExp:
|
||||||
case BuiltinObjectKind::Set:
|
case BuiltinObjectKind::Set:
|
||||||
|
case BuiltinObjectKind::SharedArrayBuffer:
|
||||||
case BuiltinObjectKind::Symbol:
|
case BuiltinObjectKind::Symbol:
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
case BuiltinObjectKind::FunctionPrototype:
|
case BuiltinObjectKind::FunctionPrototype:
|
||||||
case BuiltinObjectKind::IteratorPrototype:
|
case BuiltinObjectKind::IteratorPrototype:
|
||||||
|
case BuiltinObjectKind::ObjectPrototype:
|
||||||
|
case BuiltinObjectKind::RegExpPrototype:
|
||||||
|
case BuiltinObjectKind::StringPrototype:
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case BuiltinObjectKind::DateTimeFormatPrototype:
|
case BuiltinObjectKind::DateTimeFormatPrototype:
|
||||||
@@ -76,6 +94,12 @@ BuiltinObjectKind js::BuiltinConstructorForName(
|
|||||||
if (name == frontend::TaggedParserAtomIndex::WellKnown::Array()) {
|
if (name == frontend::TaggedParserAtomIndex::WellKnown::Array()) {
|
||||||
return BuiltinObjectKind::Array;
|
return BuiltinObjectKind::Array;
|
||||||
}
|
}
|
||||||
|
if (name == frontend::TaggedParserAtomIndex::WellKnown::ArrayBuffer()) {
|
||||||
|
return BuiltinObjectKind::ArrayBuffer;
|
||||||
|
}
|
||||||
|
if (name == frontend::TaggedParserAtomIndex::WellKnown::Int32Array()) {
|
||||||
|
return BuiltinObjectKind::Int32Array;
|
||||||
|
}
|
||||||
if (name == frontend::TaggedParserAtomIndex::WellKnown::ListFormat()) {
|
if (name == frontend::TaggedParserAtomIndex::WellKnown::ListFormat()) {
|
||||||
return BuiltinObjectKind::ListFormat;
|
return BuiltinObjectKind::ListFormat;
|
||||||
}
|
}
|
||||||
@@ -91,6 +115,9 @@ BuiltinObjectKind js::BuiltinConstructorForName(
|
|||||||
if (name == frontend::TaggedParserAtomIndex::WellKnown::Set()) {
|
if (name == frontend::TaggedParserAtomIndex::WellKnown::Set()) {
|
||||||
return BuiltinObjectKind::Set;
|
return BuiltinObjectKind::Set;
|
||||||
}
|
}
|
||||||
|
if (name == frontend::TaggedParserAtomIndex::WellKnown::SharedArrayBuffer()) {
|
||||||
|
return BuiltinObjectKind::SharedArrayBuffer;
|
||||||
|
}
|
||||||
if (name == frontend::TaggedParserAtomIndex::WellKnown::Symbol()) {
|
if (name == frontend::TaggedParserAtomIndex::WellKnown::Symbol()) {
|
||||||
return BuiltinObjectKind::Symbol;
|
return BuiltinObjectKind::Symbol;
|
||||||
}
|
}
|
||||||
@@ -105,6 +132,15 @@ BuiltinObjectKind js::BuiltinPrototypeForName(
|
|||||||
if (name == frontend::TaggedParserAtomIndex::WellKnown::Iterator()) {
|
if (name == frontend::TaggedParserAtomIndex::WellKnown::Iterator()) {
|
||||||
return BuiltinObjectKind::IteratorPrototype;
|
return BuiltinObjectKind::IteratorPrototype;
|
||||||
}
|
}
|
||||||
|
if (name == frontend::TaggedParserAtomIndex::WellKnown::Object()) {
|
||||||
|
return BuiltinObjectKind::ObjectPrototype;
|
||||||
|
}
|
||||||
|
if (name == frontend::TaggedParserAtomIndex::WellKnown::RegExp()) {
|
||||||
|
return BuiltinObjectKind::RegExpPrototype;
|
||||||
|
}
|
||||||
|
if (name == frontend::TaggedParserAtomIndex::WellKnown::String()) {
|
||||||
|
return BuiltinObjectKind::StringPrototype;
|
||||||
|
}
|
||||||
if (name == frontend::TaggedParserAtomIndex::WellKnown::DateTimeFormat()) {
|
if (name == frontend::TaggedParserAtomIndex::WellKnown::DateTimeFormat()) {
|
||||||
return BuiltinObjectKind::DateTimeFormatPrototype;
|
return BuiltinObjectKind::DateTimeFormatPrototype;
|
||||||
}
|
}
|
||||||
@@ -135,6 +171,10 @@ const char* js::BuiltinObjectName(BuiltinObjectKind kind) {
|
|||||||
switch (kind) {
|
switch (kind) {
|
||||||
case BuiltinObjectKind::Array:
|
case BuiltinObjectKind::Array:
|
||||||
return "Array";
|
return "Array";
|
||||||
|
case BuiltinObjectKind::ArrayBuffer:
|
||||||
|
return "ArrayBuffer";
|
||||||
|
case BuiltinObjectKind::Int32Array:
|
||||||
|
return "Int32Array";
|
||||||
case BuiltinObjectKind::ListFormat:
|
case BuiltinObjectKind::ListFormat:
|
||||||
return "ListFormat";
|
return "ListFormat";
|
||||||
case BuiltinObjectKind::Map:
|
case BuiltinObjectKind::Map:
|
||||||
@@ -143,6 +183,8 @@ const char* js::BuiltinObjectName(BuiltinObjectKind kind) {
|
|||||||
return "Promise";
|
return "Promise";
|
||||||
case BuiltinObjectKind::RegExp:
|
case BuiltinObjectKind::RegExp:
|
||||||
return "RegExp";
|
return "RegExp";
|
||||||
|
case BuiltinObjectKind::SharedArrayBuffer:
|
||||||
|
return "SharedArrayBuffer";
|
||||||
case BuiltinObjectKind::Set:
|
case BuiltinObjectKind::Set:
|
||||||
return "Set";
|
return "Set";
|
||||||
case BuiltinObjectKind::Symbol:
|
case BuiltinObjectKind::Symbol:
|
||||||
@@ -152,6 +194,12 @@ const char* js::BuiltinObjectName(BuiltinObjectKind kind) {
|
|||||||
return "Function.prototype";
|
return "Function.prototype";
|
||||||
case BuiltinObjectKind::IteratorPrototype:
|
case BuiltinObjectKind::IteratorPrototype:
|
||||||
return "Iterator.prototype";
|
return "Iterator.prototype";
|
||||||
|
case BuiltinObjectKind::ObjectPrototype:
|
||||||
|
return "Object.prototype";
|
||||||
|
case BuiltinObjectKind::RegExpPrototype:
|
||||||
|
return "RegExp.prototype";
|
||||||
|
case BuiltinObjectKind::StringPrototype:
|
||||||
|
return "String.prototype";
|
||||||
|
|
||||||
case BuiltinObjectKind::DateTimeFormatPrototype:
|
case BuiltinObjectKind::DateTimeFormatPrototype:
|
||||||
return "DateTimeFormat.prototype";
|
return "DateTimeFormat.prototype";
|
||||||
|
|||||||
@@ -29,16 +29,22 @@ class GlobalObject;
|
|||||||
enum class BuiltinObjectKind : uint8_t {
|
enum class BuiltinObjectKind : uint8_t {
|
||||||
// Built-in constructors.
|
// Built-in constructors.
|
||||||
Array,
|
Array,
|
||||||
|
ArrayBuffer,
|
||||||
|
Int32Array,
|
||||||
ListFormat,
|
ListFormat,
|
||||||
Map,
|
Map,
|
||||||
Promise,
|
Promise,
|
||||||
RegExp,
|
RegExp,
|
||||||
Set,
|
Set,
|
||||||
|
SharedArrayBuffer,
|
||||||
Symbol,
|
Symbol,
|
||||||
|
|
||||||
// Built-in prototypes.
|
// Built-in prototypes.
|
||||||
FunctionPrototype,
|
FunctionPrototype,
|
||||||
IteratorPrototype,
|
IteratorPrototype,
|
||||||
|
ObjectPrototype,
|
||||||
|
RegExpPrototype,
|
||||||
|
StringPrototype,
|
||||||
|
|
||||||
// Built-in Intl prototypes.
|
// Built-in Intl prototypes.
|
||||||
DateTimeFormatPrototype,
|
DateTimeFormatPrototype,
|
||||||
|
|||||||
@@ -156,7 +156,6 @@
|
|||||||
MACRO_(dollar_ArrayValues_, "$ArrayValues") \
|
MACRO_(dollar_ArrayValues_, "$ArrayValues") \
|
||||||
MACRO_(dollar_RegExpFlagsGetter_, "$RegExpFlagsGetter") \
|
MACRO_(dollar_RegExpFlagsGetter_, "$RegExpFlagsGetter") \
|
||||||
MACRO_(dollar_RegExpToString_, "$RegExpToString") \
|
MACRO_(dollar_RegExpToString_, "$RegExpToString") \
|
||||||
MACRO_(dollar_SharedArrayBufferSpecies_, "$SharedArrayBufferSpecies") \
|
|
||||||
MACRO_(domNode, "domNode") \
|
MACRO_(domNode, "domNode") \
|
||||||
MACRO_(done, "done") \
|
MACRO_(done, "done") \
|
||||||
MACRO_(dotAll, "dotAll") \
|
MACRO_(dotAll, "dotAll") \
|
||||||
|
|||||||
@@ -336,43 +336,27 @@ void js::OptimizeArraySpeciesFuse::popFuse(JSContext* cx,
|
|||||||
JSUseCounter::OPTIMIZE_ARRAY_SPECIES_FUSE);
|
JSUseCounter::OPTIMIZE_ARRAY_SPECIES_FUSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool SpeciesFuseCheckInvariant(JSContext* cx, JSProtoKey protoKey,
|
bool js::OptimizeArraySpeciesFuse::checkInvariant(JSContext* cx) {
|
||||||
PropertyName* selfHostedSpeciesAccessor) {
|
// Prototype must be Array.prototype.
|
||||||
// Prototype must be initialized.
|
auto* proto = cx->global()->maybeGetArrayPrototype();
|
||||||
auto* proto = cx->global()->maybeGetPrototype<NativeObject>(protoKey);
|
|
||||||
if (!proto) {
|
if (!proto) {
|
||||||
// No proto, invariant still holds
|
// No proto, invariant still holds
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* ctor = cx->global()->maybeGetConstructor<NativeObject>(protoKey);
|
auto* ctor = cx->global()->maybeGetConstructor<NativeObject>(JSProto_Array);
|
||||||
MOZ_ASSERT(ctor);
|
MOZ_ASSERT(ctor);
|
||||||
|
|
||||||
// Ensure the prototype's `constructor` slot is the original constructor.
|
// Ensure Array.prototype's `constructor` slot is the `Array` constructor.
|
||||||
if (!ObjectHasDataPropertyValue(proto, NameToId(cx->names().constructor),
|
if (!ObjectHasDataPropertyValue(proto, NameToId(cx->names().constructor),
|
||||||
ObjectValue(*ctor))) {
|
ObjectValue(*ctor))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure constructor's `@@species` slot is the original species getter.
|
// Ensure Array's `@@species` slot is the $ArraySpecies getter.
|
||||||
PropertyKey speciesKey = PropertyKey::Symbol(cx->wellKnownSymbols().species);
|
PropertyKey speciesKey = PropertyKey::Symbol(cx->wellKnownSymbols().species);
|
||||||
return ObjectHasGetterFunction(ctor, speciesKey, selfHostedSpeciesAccessor);
|
return ObjectHasGetterFunction(ctor, speciesKey,
|
||||||
}
|
cx->names().dollar_ArraySpecies_);
|
||||||
|
|
||||||
bool js::OptimizeArraySpeciesFuse::checkInvariant(JSContext* cx) {
|
|
||||||
return SpeciesFuseCheckInvariant(cx, JSProto_Array,
|
|
||||||
cx->names().dollar_ArraySpecies_);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool js::OptimizeArrayBufferSpeciesFuse::checkInvariant(JSContext* cx) {
|
|
||||||
return SpeciesFuseCheckInvariant(cx, JSProto_ArrayBuffer,
|
|
||||||
cx->names().dollar_ArrayBufferSpecies_);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool js::OptimizeSharedArrayBufferSpeciesFuse::checkInvariant(JSContext* cx) {
|
|
||||||
return SpeciesFuseCheckInvariant(
|
|
||||||
cx, JSProto_SharedArrayBuffer,
|
|
||||||
cx->names().dollar_SharedArrayBufferSpecies_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void js::OptimizePromiseLookupFuse::popFuse(JSContext* cx,
|
void js::OptimizePromiseLookupFuse::popFuse(JSContext* cx,
|
||||||
|
|||||||
@@ -150,34 +150,6 @@ struct OptimizeArraySpeciesFuse final : public InvalidatingRealmFuse {
|
|||||||
virtual void popFuse(JSContext* cx, RealmFuses& realmFuses) override;
|
virtual void popFuse(JSContext* cx, RealmFuses& realmFuses) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Fuse used to optimize @@species lookups for ArrayBuffers. If this fuse is
|
|
||||||
// intact, the following invariants must hold:
|
|
||||||
//
|
|
||||||
// - The builtin `ArrayBuffer.prototype` object has a `constructor` property
|
|
||||||
// that's the builtin `ArrayBuffer` constructor.
|
|
||||||
// - This `ArrayBuffer` constructor has a `Symbol.species` property that's the
|
|
||||||
// original accessor.
|
|
||||||
struct OptimizeArrayBufferSpeciesFuse final : public RealmFuse {
|
|
||||||
virtual const char* name() override {
|
|
||||||
return "OptimizeArrayBufferSpeciesFuse";
|
|
||||||
}
|
|
||||||
virtual bool checkInvariant(JSContext* cx) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Fuse used to optimize @@species lookups for SharedArrayBuffers. If this fuse
|
|
||||||
// is intact, the following invariants must hold:
|
|
||||||
//
|
|
||||||
// - The builtin `SharedArrayBuffer.prototype` object has a `constructor`
|
|
||||||
// property that's the builtin `SharedArrayBuffer` constructor.
|
|
||||||
// - This `SharedArrayBuffer` constructor has a `Symbol.species` property that's
|
|
||||||
// the original accessor.
|
|
||||||
struct OptimizeSharedArrayBufferSpeciesFuse final : public RealmFuse {
|
|
||||||
virtual const char* name() override {
|
|
||||||
return "OptimizeSharedArrayBufferSpeciesFuse";
|
|
||||||
}
|
|
||||||
virtual bool checkInvariant(JSContext* cx) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Fuse used to optimize various property lookups for promises. If this fuse is
|
// Fuse used to optimize various property lookups for promises. If this fuse is
|
||||||
// intact, the following invariants must hold:
|
// intact, the following invariants must hold:
|
||||||
//
|
//
|
||||||
@@ -309,9 +281,6 @@ struct OptimizeWeakSetPrototypeAddFuse final : public RealmFuse {
|
|||||||
FUSE(IteratorPrototypeHasObjectProto, iteratorPrototypeHasObjectProto) \
|
FUSE(IteratorPrototypeHasObjectProto, iteratorPrototypeHasObjectProto) \
|
||||||
FUSE(ObjectPrototypeHasNoReturnProperty, objectPrototypeHasNoReturnProperty) \
|
FUSE(ObjectPrototypeHasNoReturnProperty, objectPrototypeHasNoReturnProperty) \
|
||||||
FUSE(OptimizeArraySpeciesFuse, optimizeArraySpeciesFuse) \
|
FUSE(OptimizeArraySpeciesFuse, optimizeArraySpeciesFuse) \
|
||||||
FUSE(OptimizeArrayBufferSpeciesFuse, optimizeArrayBufferSpeciesFuse) \
|
|
||||||
FUSE(OptimizeSharedArrayBufferSpeciesFuse, \
|
|
||||||
optimizeSharedArrayBufferSpeciesFuse) \
|
|
||||||
FUSE(OptimizePromiseLookupFuse, optimizePromiseLookupFuse) \
|
FUSE(OptimizePromiseLookupFuse, optimizePromiseLookupFuse) \
|
||||||
FUSE(OptimizeRegExpPrototypeFuse, optimizeRegExpPrototypeFuse) \
|
FUSE(OptimizeRegExpPrototypeFuse, optimizeRegExpPrototypeFuse) \
|
||||||
FUSE(OptimizeStringPrototypeSymbolsFuse, optimizeStringPrototypeSymbolsFuse) \
|
FUSE(OptimizeStringPrototypeSymbolsFuse, optimizeStringPrototypeSymbolsFuse) \
|
||||||
|
|||||||
@@ -876,6 +876,37 @@ static bool intrinsic_GeneratorSetClosed(JSContext* cx, unsigned argc,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static bool intrinsic_ArrayBufferByteLength(JSContext* cx, unsigned argc,
|
||||||
|
Value* vp) {
|
||||||
|
CallArgs args = CallArgsFromVp(argc, vp);
|
||||||
|
MOZ_ASSERT(args.length() == 1);
|
||||||
|
MOZ_ASSERT(args[0].isObject());
|
||||||
|
MOZ_ASSERT(args[0].toObject().is<T>());
|
||||||
|
|
||||||
|
size_t byteLength = args[0].toObject().as<T>().byteLength();
|
||||||
|
args.rval().setNumber(byteLength);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static bool intrinsic_PossiblyWrappedArrayBufferByteLength(JSContext* cx,
|
||||||
|
unsigned argc,
|
||||||
|
Value* vp) {
|
||||||
|
CallArgs args = CallArgsFromVp(argc, vp);
|
||||||
|
MOZ_ASSERT(args.length() == 1);
|
||||||
|
|
||||||
|
T* obj = args[0].toObject().maybeUnwrapAs<T>();
|
||||||
|
if (!obj) {
|
||||||
|
ReportAccessDenied(cx);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t byteLength = obj->byteLength();
|
||||||
|
args.rval().setNumber(byteLength);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static void AssertNonNegativeInteger(const Value& v) {
|
static void AssertNonNegativeInteger(const Value& v) {
|
||||||
MOZ_ASSERT(v.isNumber());
|
MOZ_ASSERT(v.isNumber());
|
||||||
MOZ_ASSERT(v.toNumber() >= 0);
|
MOZ_ASSERT(v.toNumber() >= 0);
|
||||||
@@ -883,6 +914,60 @@ static void AssertNonNegativeInteger(const Value& v) {
|
|||||||
MOZ_ASSERT(JS::ToInteger(v.toNumber()) == v.toNumber());
|
MOZ_ASSERT(JS::ToInteger(v.toNumber()) == v.toNumber());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static bool intrinsic_ArrayBufferCopyData(JSContext* cx, unsigned argc,
|
||||||
|
Value* vp) {
|
||||||
|
CallArgs args = CallArgsFromVp(argc, vp);
|
||||||
|
MOZ_ASSERT(args.length() == 6);
|
||||||
|
AssertNonNegativeInteger(args[1]);
|
||||||
|
AssertNonNegativeInteger(args[3]);
|
||||||
|
AssertNonNegativeInteger(args[4]);
|
||||||
|
|
||||||
|
bool isWrapped = args[5].toBoolean();
|
||||||
|
Rooted<T*> toBuffer(cx);
|
||||||
|
if (!isWrapped) {
|
||||||
|
toBuffer = &args[0].toObject().as<T>();
|
||||||
|
} else {
|
||||||
|
JSObject* wrapped = &args[0].toObject();
|
||||||
|
MOZ_ASSERT(wrapped->is<WrapperObject>());
|
||||||
|
toBuffer = wrapped->maybeUnwrapAs<T>();
|
||||||
|
if (!toBuffer) {
|
||||||
|
ReportAccessDenied(cx);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
size_t toIndex = size_t(args[1].toNumber());
|
||||||
|
Rooted<T*> fromBuffer(cx, &args[2].toObject().as<T>());
|
||||||
|
size_t fromIndex = size_t(args[3].toNumber());
|
||||||
|
size_t count = size_t(args[4].toNumber());
|
||||||
|
|
||||||
|
T::copyData(toBuffer, toIndex, fromBuffer, fromIndex, count);
|
||||||
|
|
||||||
|
args.rval().setUndefined();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Arguments must both be SharedArrayBuffer or wrapped SharedArrayBuffer.
|
||||||
|
static bool intrinsic_SharedArrayBuffersMemorySame(JSContext* cx, unsigned argc,
|
||||||
|
Value* vp) {
|
||||||
|
CallArgs args = CallArgsFromVp(argc, vp);
|
||||||
|
MOZ_ASSERT(args.length() == 2);
|
||||||
|
|
||||||
|
auto* lhs = args[0].toObject().maybeUnwrapAs<SharedArrayBufferObject>();
|
||||||
|
if (!lhs) {
|
||||||
|
ReportAccessDenied(cx);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto* rhs = args[1].toObject().maybeUnwrapAs<SharedArrayBufferObject>();
|
||||||
|
if (!rhs) {
|
||||||
|
ReportAccessDenied(cx);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
args.rval().setBoolean(lhs->rawBufferObject() == rhs->rawBufferObject());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static bool intrinsic_IsTypedArrayConstructor(JSContext* cx, unsigned argc,
|
static bool intrinsic_IsTypedArrayConstructor(JSContext* cx, unsigned argc,
|
||||||
Value* vp) {
|
Value* vp) {
|
||||||
CallArgs args = CallArgsFromVp(argc, vp);
|
CallArgs args = CallArgsFromVp(argc, vp);
|
||||||
@@ -1903,11 +1988,18 @@ static bool intrinsic_ToTemporalDuration(JSContext* cx, unsigned argc,
|
|||||||
|
|
||||||
static const JSFunctionSpec intrinsic_functions[] = {
|
static const JSFunctionSpec intrinsic_functions[] = {
|
||||||
// Intrinsic helper functions
|
// Intrinsic helper functions
|
||||||
|
JS_INLINABLE_FN("ArrayBufferByteLength",
|
||||||
|
intrinsic_ArrayBufferByteLength<ArrayBufferObject>, 1, 0,
|
||||||
|
IntrinsicArrayBufferByteLength),
|
||||||
|
JS_FN("ArrayBufferCopyData",
|
||||||
|
intrinsic_ArrayBufferCopyData<ArrayBufferObject>, 6, 0),
|
||||||
JS_INLINABLE_FN("ArrayIteratorPrototypeOptimizable",
|
JS_INLINABLE_FN("ArrayIteratorPrototypeOptimizable",
|
||||||
intrinsic_ArrayIteratorPrototypeOptimizable, 0, 0,
|
intrinsic_ArrayIteratorPrototypeOptimizable, 0, 0,
|
||||||
IntrinsicArrayIteratorPrototypeOptimizable),
|
IntrinsicArrayIteratorPrototypeOptimizable),
|
||||||
JS_FN("AssertionFailed", intrinsic_AssertionFailed, 1, 0),
|
JS_FN("AssertionFailed", intrinsic_AssertionFailed, 1, 0),
|
||||||
JS_FN("BigIntToNumber", intrinsic_BigIntToNumber, 1, 0),
|
JS_FN("BigIntToNumber", intrinsic_BigIntToNumber, 1, 0),
|
||||||
|
JS_FN("CallArrayBufferMethodIfWrapped",
|
||||||
|
CallNonGenericSelfhostedMethod<Is<ArrayBufferObject>>, 2, 0),
|
||||||
JS_FN("CallArrayIteratorMethodIfWrapped",
|
JS_FN("CallArrayIteratorMethodIfWrapped",
|
||||||
CallNonGenericSelfhostedMethod<Is<ArrayIteratorObject>>, 2, 0),
|
CallNonGenericSelfhostedMethod<Is<ArrayIteratorObject>>, 2, 0),
|
||||||
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
|
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
|
||||||
@@ -1940,6 +2032,8 @@ static const JSFunctionSpec intrinsic_functions[] = {
|
|||||||
CallNonGenericSelfhostedMethod<Is<SetIteratorObject>>, 2, 0),
|
CallNonGenericSelfhostedMethod<Is<SetIteratorObject>>, 2, 0),
|
||||||
JS_FN("CallSetMethodIfWrapped",
|
JS_FN("CallSetMethodIfWrapped",
|
||||||
CallNonGenericSelfhostedMethod<Is<SetObject>>, 2, 0),
|
CallNonGenericSelfhostedMethod<Is<SetObject>>, 2, 0),
|
||||||
|
JS_FN("CallSharedArrayBufferMethodIfWrapped",
|
||||||
|
CallNonGenericSelfhostedMethod<Is<SharedArrayBufferObject>>, 2, 0),
|
||||||
JS_FN("CallStringIteratorMethodIfWrapped",
|
JS_FN("CallStringIteratorMethodIfWrapped",
|
||||||
CallNonGenericSelfhostedMethod<Is<StringIteratorObject>>, 2, 0),
|
CallNonGenericSelfhostedMethod<Is<StringIteratorObject>>, 2, 0),
|
||||||
JS_FN("CallTypedArrayMethodIfWrapped",
|
JS_FN("CallTypedArrayMethodIfWrapped",
|
||||||
@@ -2083,6 +2177,10 @@ static const JSFunctionSpec intrinsic_functions[] = {
|
|||||||
JS_INLINABLE_FN("IsTypedArrayConstructor",
|
JS_INLINABLE_FN("IsTypedArrayConstructor",
|
||||||
intrinsic_IsTypedArrayConstructor, 1, 0,
|
intrinsic_IsTypedArrayConstructor, 1, 0,
|
||||||
IntrinsicIsTypedArrayConstructor),
|
IntrinsicIsTypedArrayConstructor),
|
||||||
|
JS_FN("IsWrappedArrayBuffer",
|
||||||
|
intrinsic_IsWrappedInstanceOfBuiltin<ArrayBufferObject>, 1, 0),
|
||||||
|
JS_FN("IsWrappedSharedArrayBuffer",
|
||||||
|
intrinsic_IsWrappedInstanceOfBuiltin<SharedArrayBufferObject>, 1, 0),
|
||||||
JS_INLINABLE_FN("NewArrayIterator", intrinsic_NewArrayIterator, 0, 0,
|
JS_INLINABLE_FN("NewArrayIterator", intrinsic_NewArrayIterator, 0, 0,
|
||||||
IntrinsicNewArrayIterator),
|
IntrinsicNewArrayIterator),
|
||||||
JS_FN("NewAsyncIteratorHelper", intrinsic_NewAsyncIteratorHelper, 0, 0),
|
JS_FN("NewAsyncIteratorHelper", intrinsic_NewAsyncIteratorHelper, 0, 0),
|
||||||
@@ -2098,6 +2196,14 @@ static const JSFunctionSpec intrinsic_functions[] = {
|
|||||||
JS_FN("NewWrapForValidIterator", intrinsic_NewWrapForValidIterator, 0, 0),
|
JS_FN("NewWrapForValidIterator", intrinsic_NewWrapForValidIterator, 0, 0),
|
||||||
JS_FN("NoPrivateGetter", intrinsic_NoPrivateGetter, 1, 0),
|
JS_FN("NoPrivateGetter", intrinsic_NoPrivateGetter, 1, 0),
|
||||||
JS_FN("NumberToBigInt", intrinsic_NumberToBigInt, 1, 0),
|
JS_FN("NumberToBigInt", intrinsic_NumberToBigInt, 1, 0),
|
||||||
|
JS_INLINABLE_FN(
|
||||||
|
"PossiblyWrappedArrayBufferByteLength",
|
||||||
|
intrinsic_PossiblyWrappedArrayBufferByteLength<ArrayBufferObject>, 1, 0,
|
||||||
|
IntrinsicPossiblyWrappedArrayBufferByteLength),
|
||||||
|
JS_FN(
|
||||||
|
"PossiblyWrappedSharedArrayBufferByteLength",
|
||||||
|
intrinsic_PossiblyWrappedArrayBufferByteLength<SharedArrayBufferObject>,
|
||||||
|
1, 0),
|
||||||
JS_FN("PossiblyWrappedTypedArrayHasDetachedBuffer",
|
JS_FN("PossiblyWrappedTypedArrayHasDetachedBuffer",
|
||||||
intrinsic_PossiblyWrappedTypedArrayHasDetachedBuffer, 1, 0),
|
intrinsic_PossiblyWrappedTypedArrayHasDetachedBuffer, 1, 0),
|
||||||
JS_INLINABLE_FN("PossiblyWrappedTypedArrayLength",
|
JS_INLINABLE_FN("PossiblyWrappedTypedArrayLength",
|
||||||
@@ -2126,6 +2232,12 @@ static const JSFunctionSpec intrinsic_functions[] = {
|
|||||||
intrinsic_RegExpSymbolProtocolOnPrimitiveCounter, 0, 0),
|
intrinsic_RegExpSymbolProtocolOnPrimitiveCounter, 0, 0),
|
||||||
JS_INLINABLE_FN("SameValue", js::obj_is, 2, 0, ObjectIs),
|
JS_INLINABLE_FN("SameValue", js::obj_is, 2, 0, ObjectIs),
|
||||||
JS_FN("SetCopy", SetObject::copy, 1, 0),
|
JS_FN("SetCopy", SetObject::copy, 1, 0),
|
||||||
|
JS_FN("SharedArrayBufferByteLength",
|
||||||
|
intrinsic_ArrayBufferByteLength<SharedArrayBufferObject>, 1, 0),
|
||||||
|
JS_FN("SharedArrayBufferCopyData",
|
||||||
|
intrinsic_ArrayBufferCopyData<SharedArrayBufferObject>, 6, 0),
|
||||||
|
JS_FN("SharedArrayBuffersMemorySame",
|
||||||
|
intrinsic_SharedArrayBuffersMemorySame, 2, 0),
|
||||||
JS_FN("StringReplaceAllString", intrinsic_StringReplaceAllString, 3, 0),
|
JS_FN("StringReplaceAllString", intrinsic_StringReplaceAllString, 3, 0),
|
||||||
JS_INLINABLE_FN("StringReplaceString", intrinsic_StringReplaceString, 3, 0,
|
JS_INLINABLE_FN("StringReplaceString", intrinsic_StringReplaceString, 3, 0,
|
||||||
IntrinsicStringReplaceString),
|
IntrinsicStringReplaceString),
|
||||||
|
|||||||
@@ -10,8 +10,6 @@
|
|||||||
#include "mozilla/DebugOnly.h"
|
#include "mozilla/DebugOnly.h"
|
||||||
#include "mozilla/TaggedAnonymousMemory.h"
|
#include "mozilla/TaggedAnonymousMemory.h"
|
||||||
|
|
||||||
#include "jsnum.h"
|
|
||||||
|
|
||||||
#include "gc/GCContext.h"
|
#include "gc/GCContext.h"
|
||||||
#include "gc/Memory.h"
|
#include "gc/Memory.h"
|
||||||
#include "jit/AtomicOperations.h"
|
#include "jit/AtomicOperations.h"
|
||||||
@@ -21,8 +19,6 @@
|
|||||||
#include "js/SharedArrayBuffer.h"
|
#include "js/SharedArrayBuffer.h"
|
||||||
#include "util/Memory.h"
|
#include "util/Memory.h"
|
||||||
#include "util/WindowsWrapper.h"
|
#include "util/WindowsWrapper.h"
|
||||||
#include "vm/Interpreter.h"
|
|
||||||
#include "vm/SelfHosting.h"
|
|
||||||
#include "vm/SharedMem.h"
|
#include "vm/SharedMem.h"
|
||||||
#include "wasm/WasmConstants.h"
|
#include "wasm/WasmConstants.h"
|
||||||
#include "wasm/WasmMemory.h"
|
#include "wasm/WasmMemory.h"
|
||||||
@@ -434,156 +430,6 @@ bool SharedArrayBufferObject::grow(JSContext* cx, unsigned argc, Value* vp) {
|
|||||||
return CallNonGenericMethod<IsGrowableSharedArrayBuffer, growImpl>(cx, args);
|
return CallNonGenericMethod<IsGrowableSharedArrayBuffer, growImpl>(cx, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool IsSharedArrayBufferSpecies(JSContext* cx, JSFunction* species) {
|
|
||||||
return IsSelfHostedFunctionWithName(
|
|
||||||
species, cx->names().dollar_SharedArrayBufferSpecies_);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool HasBuiltinSharedArrayBufferSpecies(SharedArrayBufferObject* obj,
|
|
||||||
JSContext* cx) {
|
|
||||||
// Ensure `SharedArrayBuffer.prototype.constructor` and
|
|
||||||
// `SharedArrayBuffer[@@species]` haven't been mutated.
|
|
||||||
if (!cx->realm()->realmFuses.optimizeSharedArrayBufferSpeciesFuse.intact()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure |obj|'s prototype is the actual SharedArrayBuffer.prototype.
|
|
||||||
auto* proto = cx->global()->maybeGetPrototype(JSProto_SharedArrayBuffer);
|
|
||||||
if (!proto || obj->staticPrototype() != proto) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fail if |obj| has an own `constructor` property.
|
|
||||||
if (obj->containsPure(NameToId(cx->names().constructor))) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SharedArrayBuffer.prototype.slice ( start, end )
|
|
||||||
*
|
|
||||||
* https://tc39.es/ecma262/#sec-sharedarraybuffer.prototype.slice
|
|
||||||
*/
|
|
||||||
bool SharedArrayBufferObject::sliceImpl(JSContext* cx, const CallArgs& args) {
|
|
||||||
MOZ_ASSERT(IsSharedArrayBuffer(args.thisv()));
|
|
||||||
|
|
||||||
Rooted<SharedArrayBufferObject*> obj(
|
|
||||||
cx, &args.thisv().toObject().as<SharedArrayBufferObject>());
|
|
||||||
|
|
||||||
// Step 4.
|
|
||||||
size_t len = obj->byteLength();
|
|
||||||
|
|
||||||
// Steps 5-8.
|
|
||||||
size_t first = 0;
|
|
||||||
if (args.hasDefined(0)) {
|
|
||||||
if (!ToIntegerIndex(cx, args[0], len, &first)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Steps 9-12.
|
|
||||||
size_t final_ = len;
|
|
||||||
if (args.hasDefined(1)) {
|
|
||||||
if (!ToIntegerIndex(cx, args[1], len, &final_)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 13.
|
|
||||||
size_t newLen = final_ >= first ? final_ - first : 0;
|
|
||||||
MOZ_ASSERT(newLen <= ArrayBufferObject::ByteLengthLimit);
|
|
||||||
|
|
||||||
// Steps 14-19.
|
|
||||||
Rooted<JSObject*> resultObj(cx);
|
|
||||||
SharedArrayBufferObject* unwrappedResult = nullptr;
|
|
||||||
if (HasBuiltinSharedArrayBufferSpecies(obj, cx)) {
|
|
||||||
// Steps 14-15.
|
|
||||||
unwrappedResult = New(cx, newLen);
|
|
||||||
if (!unwrappedResult) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
resultObj.set(unwrappedResult);
|
|
||||||
|
|
||||||
// Steps 16-17. (Not applicable)
|
|
||||||
|
|
||||||
// Step 18.
|
|
||||||
MOZ_ASSERT(obj->rawBufferObject() != unwrappedResult->rawBufferObject());
|
|
||||||
|
|
||||||
// Step 19.
|
|
||||||
MOZ_ASSERT(unwrappedResult->byteLength() == newLen);
|
|
||||||
} else {
|
|
||||||
// Step 14.
|
|
||||||
Rooted<JSObject*> ctor(
|
|
||||||
cx, SpeciesConstructor(cx, obj, JSProto_SharedArrayBuffer,
|
|
||||||
IsSharedArrayBufferSpecies));
|
|
||||||
if (!ctor) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 15.
|
|
||||||
{
|
|
||||||
FixedConstructArgs<1> cargs(cx);
|
|
||||||
cargs[0].setNumber(newLen);
|
|
||||||
|
|
||||||
Rooted<Value> ctorVal(cx, ObjectValue(*ctor));
|
|
||||||
if (!Construct(cx, ctorVal, cargs, ctorVal, &resultObj)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Steps 16-17.
|
|
||||||
unwrappedResult = resultObj->maybeUnwrapIf<SharedArrayBufferObject>();
|
|
||||||
if (!unwrappedResult) {
|
|
||||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
|
|
||||||
JSMSG_NON_SHARED_ARRAY_BUFFER_RETURNED);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 18.
|
|
||||||
if (obj->rawBufferObject() == unwrappedResult->rawBufferObject()) {
|
|
||||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
|
|
||||||
JSMSG_SAME_SHARED_ARRAY_BUFFER_RETURNED);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 19.
|
|
||||||
size_t resultByteLength = unwrappedResult->byteLength();
|
|
||||||
if (resultByteLength < newLen) {
|
|
||||||
ToCStringBuf resultLenCbuf;
|
|
||||||
const char* resultLenStr =
|
|
||||||
NumberToCString(&resultLenCbuf, double(resultByteLength));
|
|
||||||
|
|
||||||
ToCStringBuf newLenCbuf;
|
|
||||||
const char* newLenStr = NumberToCString(&newLenCbuf, double(newLen));
|
|
||||||
|
|
||||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
|
|
||||||
JSMSG_SHORT_SHARED_ARRAY_BUFFER_RETURNED,
|
|
||||||
newLenStr, resultLenStr);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Steps 20-22.
|
|
||||||
SharedArrayBufferObject::copyData(unwrappedResult, 0, obj, first, newLen);
|
|
||||||
|
|
||||||
// Step 23.
|
|
||||||
args.rval().setObject(*resultObj);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SharedArrayBuffer.prototype.slice ( start, end )
|
|
||||||
*
|
|
||||||
* https://tc39.es/ecma262/#sec-sharedarraybuffer.prototype.slice
|
|
||||||
*/
|
|
||||||
bool SharedArrayBufferObject::slice(JSContext* cx, unsigned argc, Value* vp) {
|
|
||||||
// Steps 1-3.
|
|
||||||
CallArgs args = CallArgsFromVp(argc, vp);
|
|
||||||
return CallNonGenericMethod<IsSharedArrayBuffer, sliceImpl>(cx, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ES2024 draft rev 3a773fc9fae58be023228b13dbbd402ac18eeb6b
|
// ES2024 draft rev 3a773fc9fae58be023228b13dbbd402ac18eeb6b
|
||||||
// 25.2.3.1 SharedArrayBuffer ( length [ , options ] )
|
// 25.2.3.1 SharedArrayBuffer ( length [ , options ] )
|
||||||
bool SharedArrayBufferObject::class_constructor(JSContext* cx, unsigned argc,
|
bool SharedArrayBufferObject::class_constructor(JSContext* cx, unsigned argc,
|
||||||
@@ -829,10 +675,10 @@ void SharedArrayBufferObject::addSizeOfExcludingThis(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* static */
|
/* static */
|
||||||
void SharedArrayBufferObject::copyData(ArrayBufferObjectMaybeShared* toBuffer,
|
void SharedArrayBufferObject::copyData(
|
||||||
size_t toIndex,
|
Handle<ArrayBufferObjectMaybeShared*> toBuffer, size_t toIndex,
|
||||||
ArrayBufferObjectMaybeShared* fromBuffer,
|
Handle<ArrayBufferObjectMaybeShared*> fromBuffer, size_t fromIndex,
|
||||||
size_t fromIndex, size_t count) {
|
size_t count) {
|
||||||
MOZ_ASSERT(toBuffer->byteLength() >= count);
|
MOZ_ASSERT(toBuffer->byteLength() >= count);
|
||||||
MOZ_ASSERT(toBuffer->byteLength() >= toIndex + count);
|
MOZ_ASSERT(toBuffer->byteLength() >= toIndex + count);
|
||||||
MOZ_ASSERT(fromBuffer->byteLength() >= fromIndex);
|
MOZ_ASSERT(fromBuffer->byteLength() >= fromIndex);
|
||||||
@@ -936,7 +782,7 @@ static const JSPropertySpec sharedarray_properties[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static const JSFunctionSpec sharedarray_proto_functions[] = {
|
static const JSFunctionSpec sharedarray_proto_functions[] = {
|
||||||
JS_FN("slice", SharedArrayBufferObject::slice, 2, 0),
|
JS_SELF_HOSTED_FN("slice", "SharedArrayBufferSlice", 2, 0),
|
||||||
JS_FN("grow", SharedArrayBufferObject::grow, 1, 0),
|
JS_FN("grow", SharedArrayBufferObject::grow, 1, 0),
|
||||||
JS_FS_END,
|
JS_FS_END,
|
||||||
};
|
};
|
||||||
@@ -963,7 +809,6 @@ static const ClassSpec SharedArrayBufferObjectClassSpec = {
|
|||||||
sharedarray_properties,
|
sharedarray_properties,
|
||||||
sharedarray_proto_functions,
|
sharedarray_proto_functions,
|
||||||
sharedarray_proto_properties,
|
sharedarray_proto_properties,
|
||||||
GenericFinishInit<WhichHasFuseProperty::ProtoAndCtor>,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const JSClass SharedArrayBufferObject::protoClass_ = {
|
const JSClass SharedArrayBufferObject::protoClass_ = {
|
||||||
|
|||||||
@@ -255,7 +255,6 @@ class SharedArrayBufferObject : public ArrayBufferObjectMaybeShared {
|
|||||||
static bool maxByteLengthGetterImpl(JSContext* cx, const CallArgs& args);
|
static bool maxByteLengthGetterImpl(JSContext* cx, const CallArgs& args);
|
||||||
static bool growableGetterImpl(JSContext* cx, const CallArgs& args);
|
static bool growableGetterImpl(JSContext* cx, const CallArgs& args);
|
||||||
static bool growImpl(JSContext* cx, const CallArgs& args);
|
static bool growImpl(JSContext* cx, const CallArgs& args);
|
||||||
static bool sliceImpl(JSContext* cx, const CallArgs& args);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// RAWBUF_SLOT holds a pointer (as "private" data) to the
|
// RAWBUF_SLOT holds a pointer (as "private" data) to the
|
||||||
@@ -285,8 +284,6 @@ class SharedArrayBufferObject : public ArrayBufferObjectMaybeShared {
|
|||||||
|
|
||||||
static bool grow(JSContext* cx, unsigned argc, Value* vp);
|
static bool grow(JSContext* cx, unsigned argc, Value* vp);
|
||||||
|
|
||||||
static bool slice(JSContext* cx, unsigned argc, Value* vp);
|
|
||||||
|
|
||||||
static bool isOriginalByteLengthGetter(Native native) {
|
static bool isOriginalByteLengthGetter(Native native) {
|
||||||
return native == byteLengthGetter;
|
return native == byteLengthGetter;
|
||||||
}
|
}
|
||||||
@@ -328,8 +325,9 @@ class SharedArrayBufferObject : public ArrayBufferObjectMaybeShared {
|
|||||||
JS::ClassInfo* info,
|
JS::ClassInfo* info,
|
||||||
JS::RuntimeSizes* runtimeSizes);
|
JS::RuntimeSizes* runtimeSizes);
|
||||||
|
|
||||||
static void copyData(ArrayBufferObjectMaybeShared* toBuffer, size_t toIndex,
|
static void copyData(Handle<ArrayBufferObjectMaybeShared*> toBuffer,
|
||||||
ArrayBufferObjectMaybeShared* fromBuffer,
|
size_t toIndex,
|
||||||
|
Handle<ArrayBufferObjectMaybeShared*> fromBuffer,
|
||||||
size_t fromIndex, size_t count);
|
size_t fromIndex, size_t count);
|
||||||
|
|
||||||
SharedArrayRawBuffer* rawBufferObject() const;
|
SharedArrayRawBuffer* rawBufferObject() const;
|
||||||
|
|||||||
@@ -1844,6 +1844,40 @@ static bool TypedArray_set(JSContext* cx, unsigned argc, Value* vp) {
|
|||||||
return CallNonGenericMethod<IsTypedArrayObject, TypedArray_set>(cx, args);
|
return CallNonGenericMethod<IsTypedArrayObject, TypedArray_set>(cx, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert |value| to an integer and clamp it to a valid integer index within
|
||||||
|
* the range `[0..length]`.
|
||||||
|
*/
|
||||||
|
static bool ToIntegerIndex(JSContext* cx, Handle<Value> value, size_t length,
|
||||||
|
size_t* result) {
|
||||||
|
// Optimize for the common case when |value| is an int32 to avoid unnecessary
|
||||||
|
// floating point computations.
|
||||||
|
if (value.isInt32()) {
|
||||||
|
int32_t relative = value.toInt32();
|
||||||
|
|
||||||
|
if (relative >= 0) {
|
||||||
|
*result = std::min(size_t(relative), length);
|
||||||
|
} else if (mozilla::Abs(relative) <= length) {
|
||||||
|
*result = length - mozilla::Abs(relative);
|
||||||
|
} else {
|
||||||
|
*result = 0;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
double relative;
|
||||||
|
if (!ToInteger(cx, value, &relative)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (relative >= 0) {
|
||||||
|
*result = size_t(std::min(relative, double(length)));
|
||||||
|
} else {
|
||||||
|
*result = size_t(std::max(relative + double(length), 0.0));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// ES2020 draft rev dc1e21c454bd316810be1c0e7af0131a2d7f38e9
|
// ES2020 draft rev dc1e21c454bd316810be1c0e7af0131a2d7f38e9
|
||||||
// 22.2.3.5 %TypedArray%.prototype.copyWithin ( target, start [ , end ] )
|
// 22.2.3.5 %TypedArray%.prototype.copyWithin ( target, start [ , end ] )
|
||||||
static bool TypedArray_copyWithin(JSContext* cx, const CallArgs& args) {
|
static bool TypedArray_copyWithin(JSContext* cx, const CallArgs& args) {
|
||||||
|
|||||||
@@ -452,52 +452,6 @@ static void MaybePopRegExpPrototypeFuses(JSContext* cx, NativeObject* obj,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void MaybePopArrayBufferConstructorFuses(JSContext* cx,
|
|
||||||
NativeObject* obj, jsid id) {
|
|
||||||
if (obj != obj->global().maybeGetConstructor(JSProto_ArrayBuffer)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (id.isWellKnownSymbol(JS::SymbolCode::species)) {
|
|
||||||
obj->realm()->realmFuses.optimizeArrayBufferSpeciesFuse.popFuse(
|
|
||||||
cx, obj->realm()->realmFuses);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void MaybePopArrayBufferPrototypeFuses(JSContext* cx, NativeObject* obj,
|
|
||||||
jsid id) {
|
|
||||||
if (obj != obj->global().maybeGetPrototype(JSProto_ArrayBuffer)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (id.isAtom(cx->names().constructor)) {
|
|
||||||
obj->realm()->realmFuses.optimizeArrayBufferSpeciesFuse.popFuse(
|
|
||||||
cx, obj->realm()->realmFuses);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void MaybePopSharedArrayBufferConstructorFuses(JSContext* cx,
|
|
||||||
NativeObject* obj,
|
|
||||||
jsid id) {
|
|
||||||
if (obj != obj->global().maybeGetConstructor(JSProto_SharedArrayBuffer)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (id.isWellKnownSymbol(JS::SymbolCode::species)) {
|
|
||||||
obj->realm()->realmFuses.optimizeSharedArrayBufferSpeciesFuse.popFuse(
|
|
||||||
cx, obj->realm()->realmFuses);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void MaybePopSharedArrayBufferPrototypeFuses(JSContext* cx,
|
|
||||||
NativeObject* obj,
|
|
||||||
jsid id) {
|
|
||||||
if (obj != obj->global().maybeGetPrototype(JSProto_SharedArrayBuffer)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (id.isAtom(cx->names().constructor)) {
|
|
||||||
obj->realm()->realmFuses.optimizeSharedArrayBufferSpeciesFuse.popFuse(
|
|
||||||
cx, obj->realm()->realmFuses);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void MaybePopFuses(JSContext* cx, NativeObject* obj, jsid id) {
|
static void MaybePopFuses(JSContext* cx, NativeObject* obj, jsid id) {
|
||||||
// Handle writes to Array constructor fuse properties.
|
// Handle writes to Array constructor fuse properties.
|
||||||
MaybePopArrayConstructorFuses(cx, obj, id);
|
MaybePopArrayConstructorFuses(cx, obj, id);
|
||||||
@@ -534,18 +488,6 @@ static void MaybePopFuses(JSContext* cx, NativeObject* obj, jsid id) {
|
|||||||
|
|
||||||
// Handle writes to RegExp.prototype fuse properties.
|
// Handle writes to RegExp.prototype fuse properties.
|
||||||
MaybePopRegExpPrototypeFuses(cx, obj, id);
|
MaybePopRegExpPrototypeFuses(cx, obj, id);
|
||||||
|
|
||||||
// Handle writes to ArrayBuffer constructor fuse properties.
|
|
||||||
MaybePopArrayBufferConstructorFuses(cx, obj, id);
|
|
||||||
|
|
||||||
// Handle writes to ArrayBuffer.prototype fuse properties.
|
|
||||||
MaybePopArrayBufferPrototypeFuses(cx, obj, id);
|
|
||||||
|
|
||||||
// Handle writes to SharedArrayBuffer constructor fuse properties.
|
|
||||||
MaybePopSharedArrayBufferConstructorFuses(cx, obj, id);
|
|
||||||
|
|
||||||
// Handle writes to SharedArrayBuffer.prototype fuse properties.
|
|
||||||
MaybePopSharedArrayBufferPrototypeFuses(cx, obj, id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
|
|||||||
Reference in New Issue
Block a user