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;
|
||||
}
|
||||
|
||||
// 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.
|
||||
function $ArrayBufferSpecies() {
|
||||
// Step 1.
|
||||
@@ -1336,6 +1453,83 @@ function $SharedArrayBufferSpecies() {
|
||||
}
|
||||
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
|
||||
function TypedArrayCreateSameType(exemplar, length) {
|
||||
// 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_ArrayValues_:
|
||||
case WellKnownAtomId::dollar_RegExpFlagsGetter_:
|
||||
case WellKnownAtomId::dollar_RegExpToString_:
|
||||
case WellKnownAtomId::dollar_SharedArrayBufferSpecies_: {
|
||||
case WellKnownAtomId::dollar_RegExpToString_: {
|
||||
#ifdef DEBUG
|
||||
const auto& info = GetWellKnownAtomInfo(index.toWellKnownAtomId());
|
||||
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 dvLargeLength = new DataView(bufferLarge);
|
||||
|
||||
const ArrayBufferByteLength = getSelfHostedValue("ArrayBufferByteLength");
|
||||
const TypedArrayByteOffset = getSelfHostedValue("TypedArrayByteOffset");
|
||||
const TypedArrayLength = getSelfHostedValue("TypedArrayLength");
|
||||
|
||||
@@ -18,6 +19,7 @@ function testBufferByteLengthInt32() {
|
||||
var arr = [bufferLarge, bufferSmall];
|
||||
for (var i = 0; i < 2000; i++) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11122,6 +11122,45 @@ AttachDecision InlinableNativeIRGenerator::tryAttachTypedArrayLength(
|
||||
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() {
|
||||
// Self-hosted code calls this with no arguments in function scripts.
|
||||
MOZ_ASSERT(args_.length() == 0);
|
||||
@@ -12467,6 +12506,10 @@ AttachDecision InlinableNativeIRGenerator::tryAttachStub() {
|
||||
// ArrayBuffer intrinsics.
|
||||
case InlinableNative::IntrinsicGuardToArrayBuffer:
|
||||
return tryAttachGuardToArrayBuffer();
|
||||
case InlinableNative::IntrinsicArrayBufferByteLength:
|
||||
return tryAttachArrayBufferByteLength(/* isPossiblyWrapped = */ false);
|
||||
case InlinableNative::IntrinsicPossiblyWrappedArrayBufferByteLength:
|
||||
return tryAttachArrayBufferByteLength(/* isPossiblyWrapped = */ true);
|
||||
|
||||
// SharedArrayBuffer intrinsics.
|
||||
case InlinableNative::IntrinsicGuardToSharedArrayBuffer:
|
||||
|
||||
@@ -756,6 +756,7 @@ class MOZ_RAII InlinableNativeIRGenerator {
|
||||
AttachDecision tryAttachTypedArrayElementSize();
|
||||
AttachDecision tryAttachTypedArrayLength(bool isPossiblyWrapped,
|
||||
bool allowOutOfBounds);
|
||||
AttachDecision tryAttachArrayBufferByteLength(bool isPossiblyWrapped);
|
||||
AttachDecision tryAttachIsConstructing();
|
||||
AttachDecision tryAttachGetNextMapSetEntryForIterator(bool isMap);
|
||||
AttachDecision tryAttachNewArrayIterator();
|
||||
|
||||
@@ -238,6 +238,8 @@ bool js::jit::CanInlineNativeCrossRealm(InlinableNative native) {
|
||||
case InlinableNative::IntrinsicGuardToSetObject:
|
||||
case InlinableNative::IntrinsicGetNextSetEntryForIterator:
|
||||
case InlinableNative::IntrinsicGuardToArrayBuffer:
|
||||
case InlinableNative::IntrinsicArrayBufferByteLength:
|
||||
case InlinableNative::IntrinsicPossiblyWrappedArrayBufferByteLength:
|
||||
case InlinableNative::IntrinsicGuardToSharedArrayBuffer:
|
||||
case InlinableNative::IntrinsicIsTypedArrayConstructor:
|
||||
case InlinableNative::IntrinsicIsTypedArray:
|
||||
|
||||
@@ -243,6 +243,8 @@
|
||||
_(IntrinsicArrayIteratorPrototypeOptimizable) \
|
||||
\
|
||||
_(IntrinsicGuardToArrayBuffer) \
|
||||
_(IntrinsicArrayBufferByteLength) \
|
||||
_(IntrinsicPossiblyWrappedArrayBufferByteLength) \
|
||||
\
|
||||
_(IntrinsicGuardToSharedArrayBuffer) \
|
||||
\
|
||||
|
||||
@@ -2205,39 +2205,6 @@ bool js::ToIndexSlow(JSContext* cx, JS::HandleValue v,
|
||||
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>
|
||||
double js_strtod(const CharT* begin, const CharT* end, const CharT** dEnd) {
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 */
|
||||
|
||||
#endif /* jsnum_h */
|
||||
|
||||
@@ -43,10 +43,8 @@
|
||||
#include "js/Wrapper.h"
|
||||
#include "util/WindowsWrapper.h"
|
||||
#include "vm/GlobalObject.h"
|
||||
#include "vm/Interpreter.h"
|
||||
#include "vm/JSContext.h"
|
||||
#include "vm/JSObject.h"
|
||||
#include "vm/SelfHosting.h"
|
||||
#include "vm/SharedArrayObject.h"
|
||||
#include "vm/Warnings.h" // js::WarnNumberASCII
|
||||
#include "wasm/WasmConstants.h"
|
||||
@@ -331,7 +329,7 @@ static const JSPropertySpec arraybuffer_properties[] = {
|
||||
};
|
||||
|
||||
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("transfer", ArrayBufferObject::transfer, 0, 0),
|
||||
JS_FN("transferToFixedLength", ArrayBufferObject::transferToFixedLength, 0,
|
||||
@@ -361,7 +359,6 @@ static const ClassSpec ArrayBufferObjectClassSpec = {
|
||||
arraybuffer_properties,
|
||||
arraybuffer_proto_functions,
|
||||
arraybuffer_proto_properties,
|
||||
GenericFinishInit<WhichHasFuseProperty::ProtoAndCtor>,
|
||||
};
|
||||
|
||||
static const ClassExtension FixedLengthArrayBufferObjectClassExtension = {
|
||||
@@ -729,190 +726,6 @@ bool ArrayBufferObject::resize(JSContext* cx, unsigned argc, Value* vp) {
|
||||
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
|
||||
*/
|
||||
|
||||
@@ -183,7 +183,6 @@ class ArrayBufferObject : public ArrayBufferObjectMaybeShared {
|
||||
static bool maxByteLengthGetterImpl(JSContext* cx, const CallArgs& args);
|
||||
static bool resizableGetterImpl(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 transferImpl(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 slice(JSContext* cx, unsigned argc, Value* vp);
|
||||
|
||||
static bool resize(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) {
|
||||
case BuiltinObjectKind::Array:
|
||||
return JSProto_Array;
|
||||
case BuiltinObjectKind::ArrayBuffer:
|
||||
return JSProto_ArrayBuffer;
|
||||
case BuiltinObjectKind::Int32Array:
|
||||
return JSProto_Int32Array;
|
||||
case BuiltinObjectKind::ListFormat:
|
||||
return JSProto_ListFormat;
|
||||
case BuiltinObjectKind::Map:
|
||||
@@ -27,6 +31,8 @@ static JSProtoKey ToProtoKey(BuiltinObjectKind kind) {
|
||||
return JSProto_RegExp;
|
||||
case BuiltinObjectKind::Set:
|
||||
return JSProto_Set;
|
||||
case BuiltinObjectKind::SharedArrayBuffer:
|
||||
return JSProto_SharedArrayBuffer;
|
||||
case BuiltinObjectKind::Symbol:
|
||||
return JSProto_Symbol;
|
||||
|
||||
@@ -34,6 +40,12 @@ static JSProtoKey ToProtoKey(BuiltinObjectKind kind) {
|
||||
return JSProto_Function;
|
||||
case BuiltinObjectKind::IteratorPrototype:
|
||||
return JSProto_Iterator;
|
||||
case BuiltinObjectKind::ObjectPrototype:
|
||||
return JSProto_Object;
|
||||
case BuiltinObjectKind::RegExpPrototype:
|
||||
return JSProto_RegExp;
|
||||
case BuiltinObjectKind::StringPrototype:
|
||||
return JSProto_String;
|
||||
|
||||
case BuiltinObjectKind::DateTimeFormatPrototype:
|
||||
return JSProto_DateTimeFormat;
|
||||
@@ -49,16 +61,22 @@ static JSProtoKey ToProtoKey(BuiltinObjectKind kind) {
|
||||
static bool IsPrototype(BuiltinObjectKind kind) {
|
||||
switch (kind) {
|
||||
case BuiltinObjectKind::Array:
|
||||
case BuiltinObjectKind::ArrayBuffer:
|
||||
case BuiltinObjectKind::Int32Array:
|
||||
case BuiltinObjectKind::ListFormat:
|
||||
case BuiltinObjectKind::Map:
|
||||
case BuiltinObjectKind::Promise:
|
||||
case BuiltinObjectKind::RegExp:
|
||||
case BuiltinObjectKind::Set:
|
||||
case BuiltinObjectKind::SharedArrayBuffer:
|
||||
case BuiltinObjectKind::Symbol:
|
||||
return false;
|
||||
|
||||
case BuiltinObjectKind::FunctionPrototype:
|
||||
case BuiltinObjectKind::IteratorPrototype:
|
||||
case BuiltinObjectKind::ObjectPrototype:
|
||||
case BuiltinObjectKind::RegExpPrototype:
|
||||
case BuiltinObjectKind::StringPrototype:
|
||||
return true;
|
||||
|
||||
case BuiltinObjectKind::DateTimeFormatPrototype:
|
||||
@@ -76,6 +94,12 @@ BuiltinObjectKind js::BuiltinConstructorForName(
|
||||
if (name == frontend::TaggedParserAtomIndex::WellKnown::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()) {
|
||||
return BuiltinObjectKind::ListFormat;
|
||||
}
|
||||
@@ -91,6 +115,9 @@ BuiltinObjectKind js::BuiltinConstructorForName(
|
||||
if (name == frontend::TaggedParserAtomIndex::WellKnown::Set()) {
|
||||
return BuiltinObjectKind::Set;
|
||||
}
|
||||
if (name == frontend::TaggedParserAtomIndex::WellKnown::SharedArrayBuffer()) {
|
||||
return BuiltinObjectKind::SharedArrayBuffer;
|
||||
}
|
||||
if (name == frontend::TaggedParserAtomIndex::WellKnown::Symbol()) {
|
||||
return BuiltinObjectKind::Symbol;
|
||||
}
|
||||
@@ -105,6 +132,15 @@ BuiltinObjectKind js::BuiltinPrototypeForName(
|
||||
if (name == frontend::TaggedParserAtomIndex::WellKnown::Iterator()) {
|
||||
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()) {
|
||||
return BuiltinObjectKind::DateTimeFormatPrototype;
|
||||
}
|
||||
@@ -135,6 +171,10 @@ const char* js::BuiltinObjectName(BuiltinObjectKind kind) {
|
||||
switch (kind) {
|
||||
case BuiltinObjectKind::Array:
|
||||
return "Array";
|
||||
case BuiltinObjectKind::ArrayBuffer:
|
||||
return "ArrayBuffer";
|
||||
case BuiltinObjectKind::Int32Array:
|
||||
return "Int32Array";
|
||||
case BuiltinObjectKind::ListFormat:
|
||||
return "ListFormat";
|
||||
case BuiltinObjectKind::Map:
|
||||
@@ -143,6 +183,8 @@ const char* js::BuiltinObjectName(BuiltinObjectKind kind) {
|
||||
return "Promise";
|
||||
case BuiltinObjectKind::RegExp:
|
||||
return "RegExp";
|
||||
case BuiltinObjectKind::SharedArrayBuffer:
|
||||
return "SharedArrayBuffer";
|
||||
case BuiltinObjectKind::Set:
|
||||
return "Set";
|
||||
case BuiltinObjectKind::Symbol:
|
||||
@@ -152,6 +194,12 @@ const char* js::BuiltinObjectName(BuiltinObjectKind kind) {
|
||||
return "Function.prototype";
|
||||
case BuiltinObjectKind::IteratorPrototype:
|
||||
return "Iterator.prototype";
|
||||
case BuiltinObjectKind::ObjectPrototype:
|
||||
return "Object.prototype";
|
||||
case BuiltinObjectKind::RegExpPrototype:
|
||||
return "RegExp.prototype";
|
||||
case BuiltinObjectKind::StringPrototype:
|
||||
return "String.prototype";
|
||||
|
||||
case BuiltinObjectKind::DateTimeFormatPrototype:
|
||||
return "DateTimeFormat.prototype";
|
||||
|
||||
@@ -29,16 +29,22 @@ class GlobalObject;
|
||||
enum class BuiltinObjectKind : uint8_t {
|
||||
// Built-in constructors.
|
||||
Array,
|
||||
ArrayBuffer,
|
||||
Int32Array,
|
||||
ListFormat,
|
||||
Map,
|
||||
Promise,
|
||||
RegExp,
|
||||
Set,
|
||||
SharedArrayBuffer,
|
||||
Symbol,
|
||||
|
||||
// Built-in prototypes.
|
||||
FunctionPrototype,
|
||||
IteratorPrototype,
|
||||
ObjectPrototype,
|
||||
RegExpPrototype,
|
||||
StringPrototype,
|
||||
|
||||
// Built-in Intl prototypes.
|
||||
DateTimeFormatPrototype,
|
||||
|
||||
@@ -156,7 +156,6 @@
|
||||
MACRO_(dollar_ArrayValues_, "$ArrayValues") \
|
||||
MACRO_(dollar_RegExpFlagsGetter_, "$RegExpFlagsGetter") \
|
||||
MACRO_(dollar_RegExpToString_, "$RegExpToString") \
|
||||
MACRO_(dollar_SharedArrayBufferSpecies_, "$SharedArrayBufferSpecies") \
|
||||
MACRO_(domNode, "domNode") \
|
||||
MACRO_(done, "done") \
|
||||
MACRO_(dotAll, "dotAll") \
|
||||
|
||||
@@ -336,43 +336,27 @@ void js::OptimizeArraySpeciesFuse::popFuse(JSContext* cx,
|
||||
JSUseCounter::OPTIMIZE_ARRAY_SPECIES_FUSE);
|
||||
}
|
||||
|
||||
static bool SpeciesFuseCheckInvariant(JSContext* cx, JSProtoKey protoKey,
|
||||
PropertyName* selfHostedSpeciesAccessor) {
|
||||
// Prototype must be initialized.
|
||||
auto* proto = cx->global()->maybeGetPrototype<NativeObject>(protoKey);
|
||||
bool js::OptimizeArraySpeciesFuse::checkInvariant(JSContext* cx) {
|
||||
// Prototype must be Array.prototype.
|
||||
auto* proto = cx->global()->maybeGetArrayPrototype();
|
||||
if (!proto) {
|
||||
// No proto, invariant still holds
|
||||
return true;
|
||||
}
|
||||
|
||||
auto* ctor = cx->global()->maybeGetConstructor<NativeObject>(protoKey);
|
||||
auto* ctor = cx->global()->maybeGetConstructor<NativeObject>(JSProto_Array);
|
||||
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),
|
||||
ObjectValue(*ctor))) {
|
||||
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);
|
||||
return ObjectHasGetterFunction(ctor, speciesKey, selfHostedSpeciesAccessor);
|
||||
}
|
||||
|
||||
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_);
|
||||
return ObjectHasGetterFunction(ctor, speciesKey,
|
||||
cx->names().dollar_ArraySpecies_);
|
||||
}
|
||||
|
||||
void js::OptimizePromiseLookupFuse::popFuse(JSContext* cx,
|
||||
|
||||
@@ -150,34 +150,6 @@ struct OptimizeArraySpeciesFuse final : public InvalidatingRealmFuse {
|
||||
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
|
||||
// intact, the following invariants must hold:
|
||||
//
|
||||
@@ -309,9 +281,6 @@ struct OptimizeWeakSetPrototypeAddFuse final : public RealmFuse {
|
||||
FUSE(IteratorPrototypeHasObjectProto, iteratorPrototypeHasObjectProto) \
|
||||
FUSE(ObjectPrototypeHasNoReturnProperty, objectPrototypeHasNoReturnProperty) \
|
||||
FUSE(OptimizeArraySpeciesFuse, optimizeArraySpeciesFuse) \
|
||||
FUSE(OptimizeArrayBufferSpeciesFuse, optimizeArrayBufferSpeciesFuse) \
|
||||
FUSE(OptimizeSharedArrayBufferSpeciesFuse, \
|
||||
optimizeSharedArrayBufferSpeciesFuse) \
|
||||
FUSE(OptimizePromiseLookupFuse, optimizePromiseLookupFuse) \
|
||||
FUSE(OptimizeRegExpPrototypeFuse, optimizeRegExpPrototypeFuse) \
|
||||
FUSE(OptimizeStringPrototypeSymbolsFuse, optimizeStringPrototypeSymbolsFuse) \
|
||||
|
||||
@@ -876,6 +876,37 @@ static bool intrinsic_GeneratorSetClosed(JSContext* cx, unsigned argc,
|
||||
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) {
|
||||
MOZ_ASSERT(v.isNumber());
|
||||
MOZ_ASSERT(v.toNumber() >= 0);
|
||||
@@ -883,6 +914,60 @@ static void AssertNonNegativeInteger(const Value& v) {
|
||||
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,
|
||||
Value* vp) {
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
@@ -1903,11 +1988,18 @@ static bool intrinsic_ToTemporalDuration(JSContext* cx, unsigned argc,
|
||||
|
||||
static const JSFunctionSpec intrinsic_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",
|
||||
intrinsic_ArrayIteratorPrototypeOptimizable, 0, 0,
|
||||
IntrinsicArrayIteratorPrototypeOptimizable),
|
||||
JS_FN("AssertionFailed", intrinsic_AssertionFailed, 1, 0),
|
||||
JS_FN("BigIntToNumber", intrinsic_BigIntToNumber, 1, 0),
|
||||
JS_FN("CallArrayBufferMethodIfWrapped",
|
||||
CallNonGenericSelfhostedMethod<Is<ArrayBufferObject>>, 2, 0),
|
||||
JS_FN("CallArrayIteratorMethodIfWrapped",
|
||||
CallNonGenericSelfhostedMethod<Is<ArrayIteratorObject>>, 2, 0),
|
||||
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
|
||||
@@ -1940,6 +2032,8 @@ static const JSFunctionSpec intrinsic_functions[] = {
|
||||
CallNonGenericSelfhostedMethod<Is<SetIteratorObject>>, 2, 0),
|
||||
JS_FN("CallSetMethodIfWrapped",
|
||||
CallNonGenericSelfhostedMethod<Is<SetObject>>, 2, 0),
|
||||
JS_FN("CallSharedArrayBufferMethodIfWrapped",
|
||||
CallNonGenericSelfhostedMethod<Is<SharedArrayBufferObject>>, 2, 0),
|
||||
JS_FN("CallStringIteratorMethodIfWrapped",
|
||||
CallNonGenericSelfhostedMethod<Is<StringIteratorObject>>, 2, 0),
|
||||
JS_FN("CallTypedArrayMethodIfWrapped",
|
||||
@@ -2083,6 +2177,10 @@ static const JSFunctionSpec intrinsic_functions[] = {
|
||||
JS_INLINABLE_FN("IsTypedArrayConstructor",
|
||||
intrinsic_IsTypedArrayConstructor, 1, 0,
|
||||
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,
|
||||
IntrinsicNewArrayIterator),
|
||||
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("NoPrivateGetter", intrinsic_NoPrivateGetter, 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",
|
||||
intrinsic_PossiblyWrappedTypedArrayHasDetachedBuffer, 1, 0),
|
||||
JS_INLINABLE_FN("PossiblyWrappedTypedArrayLength",
|
||||
@@ -2126,6 +2232,12 @@ static const JSFunctionSpec intrinsic_functions[] = {
|
||||
intrinsic_RegExpSymbolProtocolOnPrimitiveCounter, 0, 0),
|
||||
JS_INLINABLE_FN("SameValue", js::obj_is, 2, 0, ObjectIs),
|
||||
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_INLINABLE_FN("StringReplaceString", intrinsic_StringReplaceString, 3, 0,
|
||||
IntrinsicStringReplaceString),
|
||||
|
||||
@@ -10,8 +10,6 @@
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/TaggedAnonymousMemory.h"
|
||||
|
||||
#include "jsnum.h"
|
||||
|
||||
#include "gc/GCContext.h"
|
||||
#include "gc/Memory.h"
|
||||
#include "jit/AtomicOperations.h"
|
||||
@@ -21,8 +19,6 @@
|
||||
#include "js/SharedArrayBuffer.h"
|
||||
#include "util/Memory.h"
|
||||
#include "util/WindowsWrapper.h"
|
||||
#include "vm/Interpreter.h"
|
||||
#include "vm/SelfHosting.h"
|
||||
#include "vm/SharedMem.h"
|
||||
#include "wasm/WasmConstants.h"
|
||||
#include "wasm/WasmMemory.h"
|
||||
@@ -434,156 +430,6 @@ bool SharedArrayBufferObject::grow(JSContext* cx, unsigned argc, Value* vp) {
|
||||
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
|
||||
// 25.2.3.1 SharedArrayBuffer ( length [ , options ] )
|
||||
bool SharedArrayBufferObject::class_constructor(JSContext* cx, unsigned argc,
|
||||
@@ -829,10 +675,10 @@ void SharedArrayBufferObject::addSizeOfExcludingThis(
|
||||
}
|
||||
|
||||
/* static */
|
||||
void SharedArrayBufferObject::copyData(ArrayBufferObjectMaybeShared* toBuffer,
|
||||
size_t toIndex,
|
||||
ArrayBufferObjectMaybeShared* fromBuffer,
|
||||
size_t fromIndex, size_t count) {
|
||||
void SharedArrayBufferObject::copyData(
|
||||
Handle<ArrayBufferObjectMaybeShared*> toBuffer, size_t toIndex,
|
||||
Handle<ArrayBufferObjectMaybeShared*> fromBuffer, size_t fromIndex,
|
||||
size_t count) {
|
||||
MOZ_ASSERT(toBuffer->byteLength() >= count);
|
||||
MOZ_ASSERT(toBuffer->byteLength() >= toIndex + count);
|
||||
MOZ_ASSERT(fromBuffer->byteLength() >= fromIndex);
|
||||
@@ -936,7 +782,7 @@ static const JSPropertySpec sharedarray_properties[] = {
|
||||
};
|
||||
|
||||
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_FS_END,
|
||||
};
|
||||
@@ -963,7 +809,6 @@ static const ClassSpec SharedArrayBufferObjectClassSpec = {
|
||||
sharedarray_properties,
|
||||
sharedarray_proto_functions,
|
||||
sharedarray_proto_properties,
|
||||
GenericFinishInit<WhichHasFuseProperty::ProtoAndCtor>,
|
||||
};
|
||||
|
||||
const JSClass SharedArrayBufferObject::protoClass_ = {
|
||||
|
||||
@@ -255,7 +255,6 @@ class SharedArrayBufferObject : public ArrayBufferObjectMaybeShared {
|
||||
static bool maxByteLengthGetterImpl(JSContext* cx, const CallArgs& args);
|
||||
static bool growableGetterImpl(JSContext* cx, const CallArgs& args);
|
||||
static bool growImpl(JSContext* cx, const CallArgs& args);
|
||||
static bool sliceImpl(JSContext* cx, const CallArgs& args);
|
||||
|
||||
public:
|
||||
// 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 slice(JSContext* cx, unsigned argc, Value* vp);
|
||||
|
||||
static bool isOriginalByteLengthGetter(Native native) {
|
||||
return native == byteLengthGetter;
|
||||
}
|
||||
@@ -328,8 +325,9 @@ class SharedArrayBufferObject : public ArrayBufferObjectMaybeShared {
|
||||
JS::ClassInfo* info,
|
||||
JS::RuntimeSizes* runtimeSizes);
|
||||
|
||||
static void copyData(ArrayBufferObjectMaybeShared* toBuffer, size_t toIndex,
|
||||
ArrayBufferObjectMaybeShared* fromBuffer,
|
||||
static void copyData(Handle<ArrayBufferObjectMaybeShared*> toBuffer,
|
||||
size_t toIndex,
|
||||
Handle<ArrayBufferObjectMaybeShared*> fromBuffer,
|
||||
size_t fromIndex, size_t count);
|
||||
|
||||
SharedArrayRawBuffer* rawBufferObject() const;
|
||||
|
||||
@@ -1844,6 +1844,40 @@ static bool TypedArray_set(JSContext* cx, unsigned argc, Value* vp) {
|
||||
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
|
||||
// 22.2.3.5 %TypedArray%.prototype.copyWithin ( target, start [ , end ] )
|
||||
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) {
|
||||
// Handle writes to Array constructor fuse properties.
|
||||
MaybePopArrayConstructorFuses(cx, obj, id);
|
||||
@@ -534,18 +488,6 @@ static void MaybePopFuses(JSContext* cx, NativeObject* obj, jsid id) {
|
||||
|
||||
// Handle writes to RegExp.prototype fuse properties.
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user