Skip to content
Permalink
Browse files
[JSC] Implement growable SharedArrayBuffer part 2
https://bugs.webkit.org/show_bug.cgi?id=247921
rdar://102339939

Reviewed by Mark Lam.

This patch adds runtime support for growable SharedArrayBuffer, TypedArray, and DataView.
We are not supporting JIT optimization yet, but still this patch implements the basic mechanism to support it in a subsequent patch.

1. TypedArray / DataView has a mode flag which says ResizableNonShared / GrowableShared / AutoLength etc. And we use this flag to dispatch the implementation.
   For non resizable one, we use super simple implementation as before.
2. This patch implements "auto" length, which automatically changes length / byteLength of TypedArray based on backing storage's SharedArrayBuffer etc.
3. This patch does not implement JIT optimizations. They will be done in a subsequent patch.

* JSTests/stress/detached-typed-array-iteration.js:
(shouldThrow):
* JSTests/stress/typed-array-from.js:
(shouldBeArray):
* JSTests/stress/typedarray-defineOwnProperty-error.js:
* JSTests/stress/typedarray-functions-with-neutered.js:
(checkProtoFunc.throwsCorrectError):
(checkProtoFunc):
(callWithArgs):
* JSTests/wasm/js-api/neutered-inputs.js:
* Source/JavaScriptCore/API/JSTypedArray.cpp:
(createTypedArray):
(JSObjectMakeTypedArrayWithArrayBuffer):
* Source/JavaScriptCore/builtins/ArrayIteratorPrototype.js:
(next):
* Source/JavaScriptCore/bytecode/AccessCase.cpp:
(JSC::AccessCase::generateWithGuard):
* Source/JavaScriptCore/bytecode/ArrayProfile.cpp:
(JSC::ArrayProfile::computeUpdatedPrediction):
(JSC::ArrayProfile::briefDescriptionWithoutUpdating):
* Source/JavaScriptCore/bytecode/ArrayProfile.h:
(JSC::ArrayProfile::mayBeResizableOrGrowableSharedTypedArray const):
(JSC::UnlinkedArrayProfile::update):
* Source/JavaScriptCore/bytecode/Repatch.cpp:
(JSC::tryCacheArrayGetByVal):
(JSC::tryCacheArrayPutByVal):
* Source/JavaScriptCore/bytecode/SpeculatedType.cpp:
(JSC::speculationFromClassInfoInheritance):
* Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* Source/JavaScriptCore/dfg/DFGArrayMode.cpp:
(JSC::DFG::ArrayMode::originalArrayStructure const):
(JSC::DFG::ArrayMode::dump const):
* Source/JavaScriptCore/dfg/DFGArrayMode.h:
(JSC::DFG::ArrayMode::ArrayMode):
(JSC::DFG::ArrayMode::mayBeResizableOrGrowableSharedTypedArray const):
(JSC::DFG::ArrayMode::withType const):
(JSC::DFG::ArrayMode::withSpeculation const):
(JSC::DFG::ArrayMode::withConversion const):
(JSC::DFG::ArrayMode::withTypeAndConversion const):
(JSC::DFG::ArrayMode::withArrayClassAndSpeculation const):
(JSC::DFG::ArrayMode::withProfile const):
(JSC::DFG::ArrayMode::operator== const):
(JSC::DFG::ArrayMode::withArrayClassAndSpeculationAndMayBeLargeTypedArray const): Deleted.
* Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::handleIntrinsicGetter):
(JSC::DFG::ByteCodeParser::handleTypedArrayConstructor):
* Source/JavaScriptCore/dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* Source/JavaScriptCore/dfg/DFGOperations.cpp:
(JSC::DFG::newTypedArrayWithSize):
* Source/JavaScriptCore/dfg/DFGOperations.h:
* Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::jumpForTypedArrayOutOfBounds):
(JSC::DFG::SpeculativeJIT::jumpForTypedArrayIsDetachedIfOutOfBounds):
* Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compileNewTypedArrayWithInt52Size):
(JSC::DFG::SpeculativeJIT::compileGetTypedArrayLengthAsInt52):
(JSC::DFG::SpeculativeJIT::compileGetTypedArrayByteOffsetAsInt52):
(JSC::DFG::SpeculativeJIT::compile):
* Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h:
* Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::emitGetTypedArrayByteOffsetExceptSettingResult):
(JSC::FTL::DFG::LowerDFGToB3::compileGetArrayLength):
(JSC::FTL::DFG::LowerDFGToB3::compileGetTypedArrayLengthAsInt52):
(JSC::FTL::DFG::LowerDFGToB3::compileNewTypedArray):
(JSC::FTL::DFG::LowerDFGToB3::emitNewTypedArrayWithSize):
(JSC::FTL::DFG::LowerDFGToB3::compileCompareStrictEq):
* Source/JavaScriptCore/jit/IntrinsicEmitter.cpp:
(JSC::IntrinsicGetterAccessCase::canEmitIntrinsicGetter):
(JSC::IntrinsicGetterAccessCase::emitIntrinsicGetter):
* Source/JavaScriptCore/jsc.cpp:
(JSC_DEFINE_HOST_FUNCTION):
* Source/JavaScriptCore/llint/LowLevelInterpreter.asm:
* Source/JavaScriptCore/runtime/ArrayBuffer.h:
(JSC::IdempotentArrayBufferByteLengthGetter::operator()):
(JSC::IdempotentArrayBufferByteLengthGetter::IdempotentArrayBufferByteLengthGetter): Deleted.
* Source/JavaScriptCore/runtime/ArrayBufferView.cpp:
(JSC::ArrayBufferView::ArrayBufferView):
* Source/JavaScriptCore/runtime/ArrayBufferView.h:
(JSC::ArrayBufferView::baseAddress const):
(JSC::ArrayBufferView::byteOffset const):
(JSC::ArrayBufferView::byteLength const):
(JSC::ArrayBufferView::isResizableOrGrowableShared const):
(JSC::ArrayBufferView::isResizableNonShared const):
(JSC::ArrayBufferView::isGrowableShared const):
(JSC::ArrayBufferView::isAutoLength const):
(JSC::ArrayBufferView::clampOffsetAndNumElements):
(JSC::ArrayBufferView::setImpl):
(JSC::ArrayBufferView::setRangeImpl):
* Source/JavaScriptCore/runtime/AtomicsObject.cpp:
* Source/JavaScriptCore/runtime/DataView.cpp:
(JSC::DataView::DataView):
(JSC::DataView::create):
(JSC::DataView::wrapImpl):
* Source/JavaScriptCore/runtime/DataView.h:
* Source/JavaScriptCore/runtime/GenericTypedArrayView.h:
* Source/JavaScriptCore/runtime/GenericTypedArrayViewInlines.h:
(JSC::GenericTypedArrayView<Adaptor>::GenericTypedArrayView):
(JSC::GenericTypedArrayView<Adaptor>::create):
(JSC::GenericTypedArrayView<Adaptor>::tryCreate):
(JSC::GenericTypedArrayView<Adaptor>::wrapImpl):
* Source/JavaScriptCore/runtime/JSArrayBuffer.h:
* Source/JavaScriptCore/runtime/JSArrayBufferPrototype.cpp:
(JSC::arrayBufferSlice):
(JSC::JSC_DEFINE_HOST_FUNCTION):
* Source/JavaScriptCore/runtime/JSArrayBufferView.cpp:
(JSC::JSArrayBufferView::ConstructionContext::ConstructionContext):
(JSC::JSArrayBufferView::JSArrayBufferView):
(JSC::JSArrayBufferView::finishCreation):
(JSC::JSArrayBufferView::finalize):
(JSC::JSArrayBufferView::detach):
(JSC::JSArrayBufferView::slowDownAndWasteMemory):
(JSC::JSArrayBufferView::possiblySharedImpl):
(JSC::JSArrayBufferView::isIteratorProtocolFastAndNonObservable):
(WTF::printInternal):
(JSC::JSArrayBufferView::byteLength const): Deleted.
(JSC::isIntegerIndexedObjectOutOfBounds): Deleted.
(JSC::integerIndexedObjectLength): Deleted.
(JSC::integerIndexedObjectByteLength): Deleted.
(JSC::validateTypedArray): Deleted.
* Source/JavaScriptCore/runtime/JSArrayBufferView.h:
(JSC::hasArrayBuffer):
(JSC::isResizableOrGrowableShared):
(JSC::isGrowableShared):
(JSC::isResizableNonShared):
(JSC::isAutoLength):
(JSC::isWastefulTypedArray):
(JSC::JSArrayBufferView::ConstructionContext::vector const):
(JSC::JSArrayBufferView::ConstructionContext::byteOffset const):
(JSC::JSArrayBufferView::isResizableOrGrowableShared const):
(JSC::JSArrayBufferView::isGrowableShared const):
(JSC::JSArrayBufferView::isResizableNonShared const):
(JSC::JSArrayBufferView::isAutoLength const):
(JSC::JSArrayBufferView::vector const):
(JSC::JSArrayBufferView::byteOffset const):
(JSC::JSArrayBufferView::byteOffsetRaw const):
(JSC::JSArrayBufferView::length const):
(JSC::JSArrayBufferView::lengthRaw const):
(JSC::JSArrayBufferView::byteLength const):
(JSC::JSArrayBufferView::byteLengthRaw const):
(JSC::JSArrayBufferView::offsetOfByteOffset):
(JSC::isResizable): Deleted.
(JSC::JSArrayBufferView::ConstructionContext::maxByteLength const): Deleted.
(JSC::JSArrayBufferView::ConstructionContext::maxByteLengthUnsafe const): Deleted.
(JSC::JSArrayBufferView::maxByteLength const): Deleted.
(JSC::JSArrayBufferView::offsetOfMaxByteLength): Deleted.
* Source/JavaScriptCore/runtime/JSArrayBufferViewInlines.h:
(JSC::JSArrayBufferView::isShared):
(JSC::JSArrayBufferView::possiblySharedBufferImpl):
(JSC::JSArrayBufferView::existingBufferInButterfly):
(JSC::JSArrayBufferView::toWrapped):
(JSC::JSArrayBufferView::toWrappedAllowShared):
(JSC::isIntegerIndexedObjectOutOfBounds):
(JSC::integerIndexedObjectLength):
(JSC::integerIndexedObjectByteLength):
(JSC::validateTypedArray):
(JSC::JSArrayBufferView::byteOffsetImpl): Deleted.
(JSC::JSArrayBufferView::byteOffset): Deleted.
(JSC::JSArrayBufferView::byteOffsetConcurrently): Deleted.
* Source/JavaScriptCore/runtime/JSCast.h:
* Source/JavaScriptCore/runtime/JSDataView.cpp:
(JSC::JSDataView::create):
(JSC::JSDataView::setFromTypedArray):
(JSC::JSDataView::setFromArrayLike):
(JSC::JSDataView::set): Deleted.
* Source/JavaScriptCore/runtime/JSDataView.h:
* Source/JavaScriptCore/runtime/JSDataViewPrototype.cpp:
(JSC::getData):
(JSC::setData):
(JSC::JSC_DEFINE_CUSTOM_GETTER):
(JSC::JSC_DEFINE_HOST_FUNCTION):
* Source/JavaScriptCore/runtime/JSGenericTypedArrayView.h:
(JSC::JSGenericTypedArrayView::byteLength const):
(JSC::JSGenericTypedArrayView::byteLengthRaw const):
(JSC::JSGenericTypedArrayView::inBounds const):
(JSC::JSGenericTypedArrayView::canSetIndexQuickly const):
(JSC::JSGenericTypedArrayView::getIndexQuicklyAsNativeValue const):
(JSC::JSGenericTypedArrayView::setIndexQuicklyToNativeValue):
(JSC::JSGenericTypedArrayView::sort):
(JSC::JSGenericTypedArrayView::canAccessRangeQuickly):
(JSC::JSGenericTypedArrayView::info):
(JSC::JSGenericTypedArrayView::sortFloat):
* Source/JavaScriptCore/runtime/JSGenericTypedArrayViewConstructorInlines.h:
(JSC::constructGenericTypedArrayViewWithArguments):
(JSC::constructGenericTypedArrayViewImpl):
* Source/JavaScriptCore/runtime/JSGenericTypedArrayViewInlines.h:
(JSC::JSGenericTypedArrayView<Adaptor>::create):
(JSC::JSGenericTypedArrayView<Adaptor>::setFromTypedArray):
(JSC::JSGenericTypedArrayView<Adaptor>::setFromArrayLike):
(JSC::JSGenericTypedArrayView<Adaptor>::getOwnPropertySlot):
(JSC::JSGenericTypedArrayView<Adaptor>::put):
(JSC::JSGenericTypedArrayView<Adaptor>::deleteProperty):
(JSC::JSGenericTypedArrayView<Adaptor>::getOwnPropertyNames):
(JSC::JSGenericTypedArrayView<Adaptor>::estimatedSize):
(JSC::JSGenericTypedArrayView<Adaptor>::visitChildrenImpl):
(JSC::JSGenericTypedArrayView<Adaptor>::set): Deleted.
* Source/JavaScriptCore/runtime/JSGenericTypedArrayViewPrototypeFunctions.h:
(JSC::speciesConstruct):
(JSC::genericTypedArrayViewProtoFuncSet):
(JSC::genericTypedArrayViewProtoFuncCopyWithin):
(JSC::genericTypedArrayViewProtoFuncIncludes):
(JSC::genericTypedArrayViewProtoFuncIndexOf):
(JSC::genericTypedArrayViewProtoFuncJoin):
(JSC::genericTypedArrayViewProtoFuncFill):
(JSC::genericTypedArrayViewProtoFuncLastIndexOf):
(JSC::genericTypedArrayViewProtoFuncReverse):
(JSC::genericTypedArrayViewProtoFuncToReversed):
(JSC::genericTypedArrayViewPrivateFuncClone):
(JSC::genericTypedArrayViewPrivateFuncSort):
(JSC::genericTypedArrayViewPrivateFuncFromFast):
(JSC::genericTypedArrayViewProtoFuncSlice):
(JSC::genericTypedArrayViewProtoFuncSubarray):
(JSC::validateIntegerIndex):
(JSC::genericTypedArrayViewProtoFuncWith):
* Source/JavaScriptCore/runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::init):
(JSC::JSGlobalObject::visitChildrenImpl):
* Source/JavaScriptCore/runtime/JSGlobalObject.h:
(JSC::JSGlobalObject::lazyResizableOrGrowableSharedTypedArrayStructure):
(JSC::JSGlobalObject::lazyResizableOrGrowableSharedTypedArrayStructure const):
(JSC::JSGlobalObject::typedArrayStructure const):
(JSC::JSGlobalObject::typedArrayStructureConcurrently const):
(JSC::JSGlobalObject::isOriginalTypedArrayStructure):
(JSC::JSGlobalObject::typedArrayStructureWithTypedArrayType const):
(JSC::JSGlobalObject::resizableOrGrowableSharedTypedArrayStructureWithTypedArrayType const):
* Source/JavaScriptCore/runtime/JSTypedArrayViewPrototype.cpp:
(JSC::JSC_DEFINE_HOST_FUNCTION):
(JSC::createTypedArrayIteratorObject):
* Source/JavaScriptCore/runtime/JSTypedArrays.cpp:
(): Deleted.
* Source/JavaScriptCore/runtime/JSTypedArrays.h:
(JSC::isResizableOrGrowableSharedTypedArray):
* Source/JavaScriptCore/runtime/StructureInlines.h:
(JSC::Structure::hasIndexingHeader const):
* Source/JavaScriptCore/runtime/TypedArrayAdaptors.h:
* Source/JavaScriptCore/wasm/js/JSWebAssemblyHelpers.h:
(JSC::getWasmBufferFromValue):
* Source/WTF/wtf/StdLibExtras.h:
(WTF::mask):
(WTF::roundDownToMultipleOf):
* Source/WebCore/Modules/webaudio/AudioBuffer.cpp:
(WebCore::AudioBuffer::getChannelData):
* Source/WebCore/Modules/webaudio/AudioWorkletProcessor.cpp:
(WebCore::constructJSFloat32Array):

Canonical link: https://commits.webkit.org/256766@main
  • Loading branch information
Constellation committed Nov 17, 2022
1 parent 7d62c54 commit fe4f0a4cc309e65e5bb51a15359235a52a7c8f6c
Show file tree
Hide file tree
Showing 68 changed files with 1,595 additions and 1,197 deletions.
@@ -26,6 +26,6 @@ shouldThrow(() => {
++count;
$.detachArrayBuffer(array.buffer);
}
}, `TypeError: Underlying ArrayBuffer has been detached from the view`);
}, `TypeError: Underlying ArrayBuffer has been detached from the view or out-of-bounds`);

shouldBe(count, 1);
@@ -0,0 +1,73 @@
//@ requireOptions("--useResizableArrayBuffer=1")

function shouldBe(actual, expected) {
if (actual !== expected)
throw new Error('bad value: ' + actual);
}

function shouldThrow(func, errorMessage) {
var errorThrown = false;
var error = null;
try {
func();
} catch (e) {
errorThrown = true;
error = e;
}
if (!errorThrown)
throw new Error('not thrown');
if (String(error) !== errorMessage)
throw new Error(`bad error: ${String(error)}`);
}

{
let buffer = new SharedArrayBuffer(42, { maxByteLength: 1024 });
let array = new Int8Array(buffer);
shouldBe(array.length, 42);
shouldBe(array.byteLength, 42);
buffer.grow(128);
shouldBe(array.length, 128);
shouldBe(array.byteLength, 128);
buffer.grow(1024);
shouldBe(array.length, 1024);
shouldBe(array.byteLength, 1024);
}

{
let buffer = new SharedArrayBuffer(42, { maxByteLength: 1024 });
let view = new DataView(buffer);
shouldBe(view.byteLength, 42);
buffer.grow(128);
shouldBe(view.byteLength, 128);
buffer.grow(1024);
shouldBe(view.byteLength, 1024);
}

{
let buffer = new SharedArrayBuffer(42, { maxByteLength: 1024 });
shouldThrow(() => {
let array = new Int8Array(buffer, 128);
}, `RangeError: byteOffset exceeds source ArrayBuffer byteLength`);
let array = new Int8Array(buffer, 16);
shouldBe(array.length, 26);
shouldBe(array.byteLength, 26);
buffer.grow(128);
shouldBe(array.length, 112);
shouldBe(array.byteLength, 112);
buffer.grow(1024);
shouldBe(array.length, 1008);
shouldBe(array.byteLength, 1008);
}

{
let buffer = new SharedArrayBuffer(42, { maxByteLength: 1024 });
shouldThrow(() => {
let view = new DataView(buffer, 128);
}, `RangeError: byteOffset exceeds source ArrayBuffer byteLength`);
let view = new DataView(buffer, 16);
shouldBe(view.byteLength, 26);
buffer.grow(128);
shouldBe(view.byteLength, 112);
buffer.grow(1024);
shouldBe(view.byteLength, 1008);
}
@@ -66,7 +66,7 @@ function shouldThrow(func, errorMessage) {

shouldThrow(() => {
Uint32Array.from(a0);
}, `TypeError: Underlying ArrayBuffer has been detached from the view`);
}, `TypeError: Underlying ArrayBuffer has been detached from the view or out-of-bounds`);
}

Uint8Array.prototype.__proto__[Symbol.iterator] = function *() {
@@ -22,7 +22,7 @@ testException(TA => {
let ta = new TA(4);
transferArrayBuffer(ta.buffer);
Object.defineProperty(ta, "0", {value: 1});
}, "TypeError: Underlying ArrayBuffer has been detached from the view");
}, "TypeError: Underlying ArrayBuffer has been detached from the view or out-of-bounds");

testException(TA => {
let ta = new TA(4);
@@ -57,7 +57,7 @@ function checkProtoFunc(testArgs) {
} catch (e) {
if (testArgs.error)
return e == testArgs.error;
return e == "TypeError: Underlying ArrayBuffer has been detached from the view";
return e == "TypeError: Underlying ArrayBuffer has been detached from the view or out-of-bounds";
}
return false;
}
@@ -96,7 +96,7 @@ function callWithArgs(func, array, args, argNum) {
try {
func.call(array, ...args);
} catch (e) {
if (e != "TypeError: Underlying ArrayBuffer has been detached from the view")
if (e != "TypeError: Underlying ArrayBuffer has been detached from the view or out-of-bounds")
throw new Error(e);
failed = false;
}
@@ -10,18 +10,18 @@ let neuteredArray = new Uint8Array(1);
transferArrayBuffer(neuteredArray.buffer);

const testAsyncFunction = func => {
func(neuteredArray).then(fail).catch(catcher(TypeError, "underlying TypedArray has been detatched from the ArrayBuffer"));
func(neuteredArray.buffer).then(fail).catch(catcher(TypeError, "underlying TypedArray has been detatched from the ArrayBuffer"));
func(neuteredArray).then(fail).catch(catcher(TypeError, "Underlying ArrayBuffer has been detached from the view or out-of-bounds"));
func(neuteredArray.buffer).then(fail).catch(catcher(TypeError, "Underlying ArrayBuffer has been detached from the view or out-of-bounds"));
};

const testFunction = func => {
assert.throws(() => func(neuteredArray), TypeError, "underlying TypedArray has been detatched from the ArrayBuffer");
assert.throws(() => func(neuteredArray.buffer), TypeError, "underlying TypedArray has been detatched from the ArrayBuffer");
assert.throws(() => func(neuteredArray), TypeError, "Underlying ArrayBuffer has been detached from the view or out-of-bounds");
assert.throws(() => func(neuteredArray.buffer), TypeError, "Underlying ArrayBuffer has been detached from the view or out-of-bounds");
};

const testConstructor = func => {
assert.throws(() => new func(neuteredArray), TypeError, "underlying TypedArray has been detatched from the ArrayBuffer");
assert.throws(() => new func(neuteredArray.buffer), TypeError, "underlying TypedArray has been detatched from the ArrayBuffer");
assert.throws(() => new func(neuteredArray), TypeError, "Underlying ArrayBuffer has been detached from the view or out-of-bounds");
assert.throws(() => new func(neuteredArray.buffer), TypeError, "Underlying ArrayBuffer has been detached from the view or out-of-bounds");
};

testConstructor(WebAssembly.Module);
@@ -118,7 +118,7 @@
testFailed(testName + ": set on a closed view succeeded");
return false;
} catch (xn) {
if (xn != "TypeError: Underlying ArrayBuffer has been detached from the view") {
if (xn != "TypeError: Underlying ArrayBuffer has been detached from the view or out-of-bounds") {
testFailed(testName + ": set on a closed view threw the wrong exception: " + xn);
return false;
}
@@ -107,37 +107,21 @@ inline TypedArrayType toTypedArrayType(JSTypedArrayType type)
RELEASE_ASSERT_NOT_REACHED();
}

static JSObject* createTypedArray(JSGlobalObject* globalObject, JSTypedArrayType type, RefPtr<ArrayBuffer>&& buffer, size_t offset, size_t length)
static JSObject* createTypedArray(JSGlobalObject* globalObject, JSTypedArrayType type, RefPtr<ArrayBuffer>&& buffer, size_t offset, std::optional<size_t> length)
{
VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
if (!buffer) {
throwOutOfMemoryError(globalObject, scope);
return nullptr;
}
bool isResizableOrGrowableShared = buffer->isResizableOrGrowableShared();
switch (type) {
case kJSTypedArrayTypeInt8Array:
return JSInt8Array::create(globalObject, globalObject->typedArrayStructure(TypeInt8), WTFMove(buffer), offset, length);
case kJSTypedArrayTypeInt16Array:
return JSInt16Array::create(globalObject, globalObject->typedArrayStructure(TypeInt16), WTFMove(buffer), offset, length);
case kJSTypedArrayTypeInt32Array:
return JSInt32Array::create(globalObject, globalObject->typedArrayStructure(TypeInt32), WTFMove(buffer), offset, length);
case kJSTypedArrayTypeUint8Array:
return JSUint8Array::create(globalObject, globalObject->typedArrayStructure(TypeUint8), WTFMove(buffer), offset, length);
case kJSTypedArrayTypeUint8ClampedArray:
return JSUint8ClampedArray::create(globalObject, globalObject->typedArrayStructure(TypeUint8Clamped), WTFMove(buffer), offset, length);
case kJSTypedArrayTypeUint16Array:
return JSUint16Array::create(globalObject, globalObject->typedArrayStructure(TypeUint16), WTFMove(buffer), offset, length);
case kJSTypedArrayTypeUint32Array:
return JSUint32Array::create(globalObject, globalObject->typedArrayStructure(TypeUint32), WTFMove(buffer), offset, length);
case kJSTypedArrayTypeFloat32Array:
return JSFloat32Array::create(globalObject, globalObject->typedArrayStructure(TypeFloat32), WTFMove(buffer), offset, length);
case kJSTypedArrayTypeFloat64Array:
return JSFloat64Array::create(globalObject, globalObject->typedArrayStructure(TypeFloat64), WTFMove(buffer), offset, length);
case kJSTypedArrayTypeBigInt64Array:
return JSBigInt64Array::create(globalObject, globalObject->typedArrayStructure(TypeBigInt64), WTFMove(buffer), offset, length);
case kJSTypedArrayTypeBigUint64Array:
return JSBigUint64Array::create(globalObject, globalObject->typedArrayStructure(TypeBigUint64), WTFMove(buffer), offset, length);
#define JSC_TYPED_ARRAY_FACTORY(type) case kJSTypedArrayType##type##Array: { \
return JS##type##Array::create(globalObject, globalObject->typedArrayStructure(Type##type, isResizableOrGrowableShared), WTFMove(buffer), offset, length.value()); \
}
FOR_EACH_TYPED_ARRAY_TYPE_EXCLUDING_DATA_VIEW(JSC_TYPED_ARRAY_FACTORY)
#undef JSC_TYPED_ARRAY_CHECK
case kJSTypedArrayTypeArrayBuffer:
case kJSTypedArrayTypeNone:
RELEASE_ASSERT_NOT_REACHED();
@@ -225,7 +209,10 @@ JSObjectRef JSObjectMakeTypedArrayWithArrayBuffer(JSContextRef ctx, JSTypedArray
RefPtr<ArrayBuffer> buffer = jsBuffer->impl();
unsigned elementByteSize = elementSize(toTypedArrayType(arrayType));

JSObject* result = createTypedArray(globalObject, arrayType, WTFMove(buffer), 0, buffer->byteLength() / elementByteSize);
std::optional<size_t> length;
if (!buffer->isResizableOrGrowableShared())
length = buffer->byteLength() / elementByteSize;
JSObject* result = createTypedArray(globalObject, arrayType, WTFMove(buffer), 0, length);
if (handleExceptionIfNeeded(scope, ctx, exception) == ExceptionStatus::DidThrow)
return nullptr;
return toRef(result);
@@ -286,7 +273,7 @@ size_t JSObjectGetTypedArrayByteLength(JSContextRef, JSObjectRef objectRef, JSVa
JSObject* object = toJS(objectRef);

if (JSArrayBufferView* typedArray = jsDynamicCast<JSArrayBufferView*>(object))
return typedArray->length() * elementSize(typedArray->type());
return typedArray->byteLength();

return 0;
}
@@ -33,7 +33,7 @@ function next()

var array = @getArrayIteratorInternalField(this, @arrayIteratorFieldIteratedObject);
if (@isTypedArrayView(array) && @isDetached(array))
@throwTypeError("Underlying ArrayBuffer has been detached from the view");
@throwTypeError("Underlying ArrayBuffer has been detached from the view or out-of-bounds");

var kind = @getArrayIteratorInternalField(this, @arrayIteratorFieldKind);
return @arrayIteratorNextHelper.@call(this, array, kind);
@@ -1218,8 +1218,8 @@ void AccessCase::generateWithGuard(

GPRReg propertyGPR = stubInfo.propertyGPR();

jit.load8(CCallHelpers::Address(baseGPR, JSCell::typeInfoTypeOffset()), scratchGPR);
fallThrough.append(jit.branch32(CCallHelpers::NotEqual, scratchGPR, CCallHelpers::TrustedImm32(typeForTypedArrayType(type))));
fallThrough.append(jit.branch8(CCallHelpers::NotEqual, CCallHelpers::Address(baseGPR, JSCell::typeInfoTypeOffset()), CCallHelpers::TrustedImm32(typeForTypedArrayType(type))));
fallThrough.append(jit.branchTest8(CCallHelpers::NonZero, CCallHelpers::Address(baseGPR, JSArrayBufferView::offsetOfMode()), CCallHelpers::TrustedImm32(isResizableOrGrowableSharedMode)));

CCallHelpers::Address addressOfLength = CCallHelpers::Address(baseGPR, JSArrayBufferView::offsetOfLength());
jit.signExtend32ToPtr(propertyGPR, scratchGPR);
@@ -1237,9 +1237,9 @@ void AccessCase::generateWithGuard(
jit, ScratchRegisterAllocator::ExtraStackSpace::NoExtraSpace);

#if USE(LARGE_TYPED_ARRAYS)
jit.load64(CCallHelpers::Address(baseGPR, JSArrayBufferView::offsetOfMaxByteLength()), scratchGPR);
jit.load64(CCallHelpers::Address(baseGPR, JSArrayBufferView::offsetOfLength()), scratchGPR);
#else
jit.load32(CCallHelpers::Address(baseGPR, JSArrayBufferView::offsetOfMaxByteLength()), scratchGPR);
jit.load32(CCallHelpers::Address(baseGPR, JSArrayBufferView::offsetOfLength()), scratchGPR);
#endif
jit.loadPtr(CCallHelpers::Address(baseGPR, JSArrayBufferView::offsetOfVector()), scratch2GPR);
jit.cageConditionallyAndUntag(Gigacage::Primitive, scratch2GPR, scratchGPR, scratchGPR, false);
@@ -1625,8 +1625,8 @@ void AccessCase::generateWithGuard(

GPRReg propertyGPR = stubInfo.propertyGPR();

jit.load8(CCallHelpers::Address(baseGPR, JSCell::typeInfoTypeOffset()), scratchGPR);
fallThrough.append(jit.branch32(CCallHelpers::NotEqual, scratchGPR, CCallHelpers::TrustedImm32(typeForTypedArrayType(type))));
fallThrough.append(jit.branch8(CCallHelpers::NotEqual, CCallHelpers::Address(baseGPR, JSCell::typeInfoTypeOffset()), CCallHelpers::TrustedImm32(typeForTypedArrayType(type))));
fallThrough.append(jit.branchTest8(CCallHelpers::NonZero, CCallHelpers::Address(baseGPR, JSArrayBufferView::offsetOfMode()), CCallHelpers::TrustedImm32(isResizableOrGrowableSharedMode)));

if (isInt(type))
state.failAndRepatch.append(jit.branchIfNotInt32(valueRegs));
@@ -1663,9 +1663,9 @@ void AccessCase::generateWithGuard(
jit, ScratchRegisterAllocator::ExtraStackSpace::NoExtraSpace);

#if USE(LARGE_TYPED_ARRAYS)
jit.load64(CCallHelpers::Address(baseGPR, JSArrayBufferView::offsetOfMaxByteLength()), scratchGPR);
jit.load64(CCallHelpers::Address(baseGPR, JSArrayBufferView::offsetOfLength()), scratchGPR);
#else
jit.load32(CCallHelpers::Address(baseGPR, JSArrayBufferView::offsetOfMaxByteLength()), scratchGPR);
jit.load32(CCallHelpers::Address(baseGPR, JSArrayBufferView::offsetOfLength()), scratchGPR);
#endif
jit.loadPtr(CCallHelpers::Address(baseGPR, JSArrayBufferView::offsetOfVector()), scratch2GPR);
jit.cageConditionallyAndUntag(Gigacage::Primitive, scratch2GPR, scratchGPR, scratchGPR, false);
@@ -28,6 +28,7 @@

#include "CodeBlock.h"
#include "JSCellInlines.h"
#include "JSTypedArrays.h"
#include <wtf/CommaPrinter.h>
#include <wtf/StringPrintStream.h>

@@ -140,8 +141,14 @@ void ArrayProfile::computeUpdatedPrediction(const ConcurrentJSLocker&, CodeBlock
m_arrayProfileFlags.add(ArrayProfileFlag::MayInterceptIndexedAccesses);

JSGlobalObject* globalObject = codeBlock->globalObject();
if (!globalObject->isOriginalArrayStructure(lastSeenStructure) && !globalObject->isOriginalTypedArrayStructure(lastSeenStructure))
bool isResizableOrGrowableShared = false;
if (!globalObject->isOriginalArrayStructure(lastSeenStructure) && !globalObject->isOriginalTypedArrayStructure(lastSeenStructure, isResizableOrGrowableShared))
m_arrayProfileFlags.add(ArrayProfileFlag::UsesNonOriginalArrayStructures);

if (isTypedArrayTypeIncludingDataView(lastSeenStructure->typeInfo().type())) {
if (isResizableOrGrowableSharedTypedArrayIncludingDataView(lastSeenStructure->classInfoForCells()))
m_arrayProfileFlags.add(ArrayProfileFlag::MayBeResizableOrGrowableSharedTypedArray);
}
}

void ArrayProfile::observeIndexedRead(JSCell* cell, unsigned index)
@@ -182,6 +189,8 @@ CString ArrayProfile::briefDescriptionWithoutUpdating(const ConcurrentJSLocker&)
out.print(comma, "Intercept");
if (!m_arrayProfileFlags.contains(ArrayProfileFlag::UsesNonOriginalArrayStructures))
out.print(comma, "Original");
if (!m_arrayProfileFlags.contains(ArrayProfileFlag::MayBeResizableOrGrowableSharedTypedArray))
out.print(comma, "Resizable");

return out.toCString();
}
@@ -201,7 +201,8 @@ enum class ArrayProfileFlag : uint32_t {
MayBeLargeTypedArray = 1 << 2,
MayInterceptIndexedAccesses = 1 << 3,
UsesNonOriginalArrayStructures = 1 << 4,
DidPerformFirstRunPruning = 1 << 5,
MayBeResizableOrGrowableSharedTypedArray = 1 << 5,
DidPerformFirstRunPruning = 1 << 6,
};

class ArrayProfile {
@@ -214,6 +215,8 @@ class ArrayProfile {
void setMayBeLargeTypedArray() { m_arrayProfileFlags.add(ArrayProfileFlag::MayBeLargeTypedArray); }
bool mayBeLargeTypedArray(const ConcurrentJSLocker&) const { return m_arrayProfileFlags.contains(ArrayProfileFlag::MayBeLargeTypedArray); }

bool mayBeResizableOrGrowableSharedTypedArray(const ConcurrentJSLocker&) const { return m_arrayProfileFlags.contains(ArrayProfileFlag::MayBeResizableOrGrowableSharedTypedArray); }

StructureID* addressOfLastSeenStructureID() { return &m_lastSeenStructureID; }
ArrayModes* addressOfArrayModes() { return &m_observedArrayModes; }

@@ -263,42 +266,15 @@ class UnlinkedArrayProfile {
m_observedArrayModes = newModes;
arrayProfile.m_observedArrayModes = newModes;

if (m_mayStoreToHole)
arrayProfile.m_arrayProfileFlags.add(ArrayProfileFlag::MayStoreHole);
else
m_mayStoreToHole = arrayProfile.m_arrayProfileFlags.contains(ArrayProfileFlag::MayStoreHole);

if (m_outOfBounds)
arrayProfile.m_arrayProfileFlags.add(ArrayProfileFlag::OutOfBounds);
else
m_outOfBounds = arrayProfile.m_arrayProfileFlags.contains(ArrayProfileFlag::OutOfBounds);

if (m_mayInterceptIndexedAccesses)
arrayProfile.m_arrayProfileFlags.add(ArrayProfileFlag::MayInterceptIndexedAccesses);
else
m_mayInterceptIndexedAccesses = arrayProfile.m_arrayProfileFlags.contains(ArrayProfileFlag::MayInterceptIndexedAccesses);

if (m_usesNonOriginalArrayStructures)
arrayProfile.m_arrayProfileFlags.add(ArrayProfileFlag::UsesNonOriginalArrayStructures);
else
m_usesNonOriginalArrayStructures = arrayProfile.m_arrayProfileFlags.contains(ArrayProfileFlag::UsesNonOriginalArrayStructures);

if (m_mayBeLargeTypedArray)
arrayProfile.m_arrayProfileFlags.add(ArrayProfileFlag::MayBeLargeTypedArray);
else
m_mayBeLargeTypedArray = arrayProfile.m_arrayProfileFlags.contains(ArrayProfileFlag::MayBeLargeTypedArray);
arrayProfile.m_arrayProfileFlags.add(m_arrayProfileFlags);
auto unlinkedArrayProfileFlags = arrayProfile.m_arrayProfileFlags;
unlinkedArrayProfileFlags.remove(ArrayProfileFlag::DidPerformFirstRunPruning); // We do not propagate DidPerformFirstRunPruning.
m_arrayProfileFlags = unlinkedArrayProfileFlags;
}

private:
ArrayModes m_observedArrayModes { 0 };
// We keep these as full byte-sized booleans just for speed, because the
// alignment of this struct will already make us 8 bytes large. But if we
// ever need to add more stuff, these fields can become bitfields.
bool m_mayStoreToHole { false };
bool m_outOfBounds { false };
bool m_mayInterceptIndexedAccesses { false };
bool m_usesNonOriginalArrayStructures : 1 { false };
bool m_mayBeLargeTypedArray : 1 { false };
OptionSet<ArrayProfileFlag> m_arrayProfileFlags { };
};
static_assert(sizeof(UnlinkedArrayProfile) <= 8);

0 comments on commit fe4f0a4

Please sign in to comment.