Skip to content
Permalink
Browse files
Remove per-iteration detached buffer check in %TypedArray% set and so…
…rt methods

https://bugs.webkit.org/show_bug.cgi?id=240995

Reviewed by Yusuke Suzuki.

This patch implements the spec changes of tc39/ecma262#2646 and tc39/ecma262#2723:
%TypedArray%.prototype.{set, sort} no longer repeatedly check for detachment as they iterate through a buffer.

* JSTests/stress/typedarray-functions-with-neutered.js:
* JSTests/test262/expectations.yaml:
* LayoutTests/js/typed-array-mutated-during-set.html:
* LayoutTests/js/typed-array-mutated-during-set-expected.txt:
* Source/JavaScriptCore/builtins/TypedArrayPrototype.js:
(globalPrivate.typedArrayMerge):
(globalPrivate.typedArrayElementCompare): Deleted.
* Source/JavaScriptCore/runtime/JSGenericTypedArrayView.h:
* Source/JavaScriptCore/runtime/JSGenericTypedArrayViewInlines.h:
(JSC::JSGenericTypedArrayView<Adaptor>::set):

Canonical link: https://commits.webkit.org/251044@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@294933 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
rkirsling committed May 27, 2022
1 parent d726f6c commit 76d4af85b30e938c520f5743482f60923dc06db9
Showing 7 changed files with 13 additions and 37 deletions.
@@ -77,9 +77,7 @@ for (var i = 0; i < 1000; i++)
prototypeFunctions = [
{ func:proto.copyWithin, args:["prim", "prim", "prim"] },
{ func:proto.fill, args:["prim", "prim", "prim"] },
{ func:proto.set, args:["array", "prim"] },
{ func:proto.slice, args:["prim", "prim"] },
{ func:proto.sort, args:["func"] },
{ func:proto.subarray, args:["prim", "prim"] },
];

@@ -1092,12 +1092,6 @@ test/built-ins/Temporal/PlainTime/prototype/until/argument-zoneddatetime-timezon
test/built-ins/Temporal/getOwnPropertyNames.js:
default: 'Test262Error: PlainDateTime'
strict mode: 'Test262Error: PlainDateTime'
test/built-ins/TypedArray/prototype/set/array-arg-targetbuffer-detached-on-get-src-value-no-throw.js:
default: 'TypeError: Underlying ArrayBuffer has been detached from the view (Testing with Float64Array.)'
strict mode: 'TypeError: Underlying ArrayBuffer has been detached from the view (Testing with Float64Array.)'
test/built-ins/TypedArray/prototype/sort/sort-tonumber.js:
default: 'TypeError: Underlying ArrayBuffer has been detached from the view (Testing with Float64Array.)'
strict mode: 'TypeError: Underlying ArrayBuffer has been detached from the view (Testing with Float64Array.)'
test/harness/temporalHelpers-one-shift-time-zone.js:
default: "TypeError: undefined is not a constructor (evaluating 'new Temporal.PlainDateTime(2021, 3, 28, 1)')"
strict mode: "TypeError: undefined is not a constructor (evaluating 'new Temporal.PlainDateTime(2021, 3, 28, 1)')"
@@ -5,7 +5,7 @@ On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE

PASS buffer.byteLength is 100
PASS buffer.byteLength is 0
PASS byteArray.set(array) threw exception TypeError: Underlying ArrayBuffer has been detached from the view.
PASS byteArray.set(array) threw exception success.
PASS successfullyParsed is true

TEST COMPLETE
@@ -22,7 +22,7 @@
};
var errorCreator = {
valueOf: function() {
throw "fail"
throw "success";
}
};

@@ -166,19 +166,6 @@ function some(callback /* [, thisArg] */)
return false;
}

@globalPrivate
function typedArrayElementCompare(array, a, b, comparator)
{
"use strict";

var result = @toNumber(comparator(a, b));

if (@isDetached(array))
@throwTypeError("Underlying ArrayBuffer has been detached from the view");

return result;
}

@globalPrivate
function typedArrayMerge(array, dst, src, srcIndex, srcEnd, width, comparator)
{
@@ -191,7 +178,7 @@ function typedArrayMerge(array, dst, src, srcIndex, srcEnd, width, comparator)

for (var dstIndex = left; dstIndex < rightEnd; ++dstIndex) {
if (right < rightEnd) {
if (left >= leftEnd || @typedArrayElementCompare(array, src[right], src[left], comparator) < 0) {
if (left >= leftEnd || @toNumber(comparator(src[right], src[left])) < 0) {
dst[dstIndex] = src[right++];
continue;
}
@@ -170,7 +170,10 @@ class JSGenericTypedArrayView final : public JSArrayBufferView {
typename Adaptor::Type value = toNativeFromValue<Adaptor>(globalObject, jsValue);
RETURN_IF_EXCEPTION(scope, false);

if (isDetached() || i >= m_length)
if (isDetached())
return true;

if (i >= m_length)
return false;

setIndexQuicklyToNativeValue(i, value);
@@ -324,16 +324,6 @@ bool JSGenericTypedArrayView<Adaptor>::set(
if (!success)
return false;

auto trySetIndex = [&](size_t index, JSValue value) -> bool {
bool success = setIndex(globalObject, index, value);
EXCEPTION_ASSERT(!scope.exception() || !success);
if (!success) {
if (isDetached())
throwTypeError(globalObject, scope, typedArrayBufferHasBeenDetachedErrorMessage);
return false;
}
return true;
};
// It is not valid to ever call object->get() with an index of more than MAX_ARRAY_INDEX.
// So we iterate in the optimized loop up to MAX_ARRAY_INDEX, then if there is anything to do beyond this, we rely on slower code.
size_t safeUnadjustedLength = std::min(length, static_cast<size_t>(MAX_ARRAY_INDEX) + 1);
@@ -342,14 +332,18 @@ bool JSGenericTypedArrayView<Adaptor>::set(
ASSERT(i + objectOffset <= MAX_ARRAY_INDEX);
JSValue value = object->get(globalObject, static_cast<unsigned>(i + objectOffset));
RETURN_IF_EXCEPTION(scope, false);
if (!trySetIndex(offset + i, value))
bool success = setIndex(globalObject, offset + i, value);
EXCEPTION_ASSERT(!scope.exception() || !success);
if (!success)
return false;
}
for (size_t i = safeLength; i < length; ++i) {
Identifier ident = Identifier::from(vm, static_cast<uint64_t>(i + objectOffset));
JSValue value = object->get(globalObject, ident);
RETURN_IF_EXCEPTION(scope, false);
if (!trySetIndex(offset + i, value))
bool success = setIndex(globalObject, offset + i, value);
EXCEPTION_ASSERT(!scope.exception() || !success);
if (!success)
return false;
}
return true;

0 comments on commit 76d4af8

Please sign in to comment.