From 0a5fc847a2887f521d13d1d6e7b51c253a702a7c Mon Sep 17 00:00:00 2001 From: =?utf8?q?Andr=C3=A9=20Bargull?= Date: Thu, 25 Jan 2024 15:49:48 +0000 Subject: [PATCH] Bug 1842773 - Part 15: Support resizable TypedArrays in MacroAssembler. r=sfink,jandem It's easy to add support for resizable typed arrays to `branchIfClassIsNotTypedArray`, because the classes are in contiguous memory. `MacroAssembler::typedArrayElementSize` is a bit more difficult, at least when trying to avoid duplicating the detection for both fixed length and resizable typed array classes. Differential Revision: https://phabricator.services.mozilla.com/D183331 --- js/src/jit/CacheIR.cpp | 5 --- js/src/jit/MacroAssembler.cpp | 92 +++++++++++++++++++++++++++++------------- js/src/vm/TypedArrayObject.cpp | 4 +- js/src/vm/TypedArrayObject.h | 6 --- 4 files changed, 68 insertions(+), 39 deletions(-) diff --git a/js/src/jit/CacheIR.cpp b/js/src/jit/CacheIR.cpp index 98c4513443b3..b4956456a3e9 100644 --- a/js/src/jit/CacheIR.cpp +++ b/js/src/jit/CacheIR.cpp @@ -10073,11 +10073,6 @@ AttachDecision InlinableNativeIRGenerator::tryAttachTypedArrayElementSize() { MOZ_ASSERT(args_[0].isObject()); MOZ_ASSERT(args_[0].toObject().is()); - // TODO: Support resizable buffers. - if (!args_[0].toObject().is()) { - return AttachDecision::NoAction; - } - // Initialize the input operand. initializeInputOperand(); diff --git a/js/src/jit/MacroAssembler.cpp b/js/src/jit/MacroAssembler.cpp index 293a3a522c4b..59516e0bd5bf 100644 --- a/js/src/jit/MacroAssembler.cpp +++ b/js/src/jit/MacroAssembler.cpp @@ -7416,41 +7416,80 @@ static constexpr bool ValidateSizeRange(Scalar::Type from, Scalar::Type to) { } void MacroAssembler::typedArrayElementSize(Register obj, Register output) { - static_assert(Scalar::Int8 == 0, "Int8 is the first typed array class"); - static_assert( - (Scalar::BigUint64 - Scalar::Int8) == Scalar::MaxTypedArrayViewType - 1, - "BigUint64 is the last typed array class"); + loadObjClassUnsafe(obj, output); - Label one, two, four, eight, done; + // Map resizable to fixed-length TypedArray classes. + Label fixedLength; + branchPtr(Assembler::Below, output, + ImmPtr(std::end(TypedArrayObject::fixedLengthClasses)), + &fixedLength); + { + MOZ_ASSERT(std::end(TypedArrayObject::fixedLengthClasses) == + std::begin(TypedArrayObject::resizableClasses), + "TypedArray classes are in contiguous memory"); - // TODO(anba): Handle resizable TypedArrays - loadObjClassUnsafe(obj, output); + const auto* firstFixedLengthTypedArrayClass = + std::begin(TypedArrayObject::fixedLengthClasses); + const auto* firstResizableTypedArrayClass = + std::begin(TypedArrayObject::resizableClasses); + + MOZ_ASSERT(firstFixedLengthTypedArrayClass < firstResizableTypedArrayClass); + + ptrdiff_t diff = + firstResizableTypedArrayClass - firstFixedLengthTypedArrayClass; + + mozilla::CheckedInt checked = diff; + checked *= sizeof(JSClass); + MOZ_ASSERT(checked.isValid(), "pointer difference fits in int32"); + + subPtr(Imm32(int32_t(checked.value())), output); + } + bind(&fixedLength); + +#ifdef DEBUG + Label invalidClass, validClass; + branchPtr(Assembler::Below, output, + ImmPtr(std::begin(TypedArrayObject::fixedLengthClasses)), + &invalidClass); + branchPtr(Assembler::Below, output, + ImmPtr(std::end(TypedArrayObject::fixedLengthClasses)), + &validClass); + bind(&invalidClass); + assumeUnreachable("value isn't a valid FixedLengthTypedArray class"); + bind(&validClass); +#endif + + auto classForType = [](Scalar::Type type) { + MOZ_ASSERT(type < Scalar::MaxTypedArrayViewType); + return &TypedArrayObject::fixedLengthClasses[type]; + }; + + Label one, two, four, eight, done; static_assert(ValidateSizeRange(Scalar::Int8, Scalar::Int16), "element size is one in [Int8, Int16)"); - branchPtr(Assembler::Below, output, - ImmPtr(TypedArrayObject::classForType(Scalar::Int16)), &one); + branchPtr(Assembler::Below, output, ImmPtr(classForType(Scalar::Int16)), + &one); static_assert(ValidateSizeRange(Scalar::Int16, Scalar::Int32), "element size is two in [Int16, Int32)"); - branchPtr(Assembler::Below, output, - ImmPtr(TypedArrayObject::classForType(Scalar::Int32)), &two); + branchPtr(Assembler::Below, output, ImmPtr(classForType(Scalar::Int32)), + &two); static_assert(ValidateSizeRange(Scalar::Int32, Scalar::Float64), "element size is four in [Int32, Float64)"); - branchPtr(Assembler::Below, output, - ImmPtr(TypedArrayObject::classForType(Scalar::Float64)), &four); + branchPtr(Assembler::Below, output, ImmPtr(classForType(Scalar::Float64)), + &four); static_assert(ValidateSizeRange(Scalar::Float64, Scalar::Uint8Clamped), "element size is eight in [Float64, Uint8Clamped)"); branchPtr(Assembler::Below, output, - ImmPtr(TypedArrayObject::classForType(Scalar::Uint8Clamped)), - &eight); + ImmPtr(classForType(Scalar::Uint8Clamped)), &eight); static_assert(ValidateSizeRange(Scalar::Uint8Clamped, Scalar::BigInt64), "element size is one in [Uint8Clamped, BigInt64)"); - branchPtr(Assembler::Below, output, - ImmPtr(TypedArrayObject::classForType(Scalar::BigInt64)), &one); + branchPtr(Assembler::Below, output, ImmPtr(classForType(Scalar::BigInt64)), + &one); static_assert( ValidateSizeRange(Scalar::BigInt64, Scalar::MaxTypedArrayViewType), @@ -7477,16 +7516,15 @@ void MacroAssembler::typedArrayElementSize(Register obj, Register output) { void MacroAssembler::branchIfClassIsNotTypedArray(Register clasp, Label* notTypedArray) { - // TODO(anba): Handle resizable TypedArrays - static_assert(Scalar::Int8 == 0, "Int8 is the first typed array class"); - const JSClass* firstTypedArrayClass = - TypedArrayObject::classForType(Scalar::Int8); - - static_assert( - (Scalar::BigUint64 - Scalar::Int8) == Scalar::MaxTypedArrayViewType - 1, - "BigUint64 is the last typed array class"); - const JSClass* lastTypedArrayClass = - TypedArrayObject::classForType(Scalar::BigUint64); + // Inline implementation of IsTypedArrayClass(). + + const auto* firstTypedArrayClass = + std::begin(TypedArrayObject::fixedLengthClasses); + const auto* lastTypedArrayClass = + std::prev(std::end(TypedArrayObject::resizableClasses)); + MOZ_ASSERT(std::end(TypedArrayObject::fixedLengthClasses) == + std::begin(TypedArrayObject::resizableClasses), + "TypedArray classes are in contiguous memory"); branchPtr(Assembler::Below, clasp, ImmPtr(firstTypedArrayClass), notTypedArray); diff --git a/js/src/vm/TypedArrayObject.cpp b/js/src/vm/TypedArrayObject.cpp index 10b7b0d94109..3d0edee2a5fb 100644 --- a/js/src/vm/TypedArrayObject.cpp +++ b/js/src/vm/TypedArrayObject.cpp @@ -809,7 +809,9 @@ class FixedLengthTypedArrayObjectTemplate using TypedArrayTemplate::protoKey; static inline const JSClass* instanceClass() { - return TypedArrayObject::classForType(ArrayTypeID()); + static_assert(ArrayTypeID() < + std::size(TypedArrayObject::fixedLengthClasses)); + return &TypedArrayObject::fixedLengthClasses[ArrayTypeID()]; } static TypedArrayObject* newBuiltinClassInstance(JSContext* cx, diff --git a/js/src/vm/TypedArrayObject.h b/js/src/vm/TypedArrayObject.h index 1a780733befb..be5b2d38ab79 100644 --- a/js/src/vm/TypedArrayObject.h +++ b/js/src/vm/TypedArrayObject.h @@ -58,12 +58,6 @@ class TypedArrayObject : public ArrayBufferViewObject { static const JSClass protoClasses[Scalar::MaxTypedArrayViewType]; static const JSClass sharedTypedArrayPrototypeClass; - // TODO(anba): Integrate with resizable TypedArrays - static const JSClass* classForType(Scalar::Type type) { - MOZ_ASSERT(type < Scalar::MaxTypedArrayViewType); - return &fixedLengthClasses[type]; - } - static const JSClass* protoClassForType(Scalar::Type type) { MOZ_ASSERT(type < Scalar::MaxTypedArrayViewType); return &protoClasses[type]; -- 2.11.4.GIT