From 22f326b8af3baafa5968003d61403175bc10d6dd Mon Sep 17 00:00:00 2001 From: Maya Lekova Date: Tue, 10 Aug 2021 16:03:58 +0200 Subject: [PATCH] [fastcall] Add 8-byte element types support for TypedArrays This CL adds back the 8-byte element types and extends the fast API by hiding the unaligned memory reads performed for them. Bug: chromium:1052746 Change-Id: Ide49ce6bd2c77b9d2d544ca2df47b5f95c93eaa9 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3056988 Commit-Queue: Maya Lekova Reviewed-by: Camillo Bruni Reviewed-by: Leszek Swirski Reviewed-by: Georg Neis Cr-Commit-Position: refs/heads/master@{#76207} --- include/v8-fast-api-calls.h | 38 +++++++++++++++++-- src/api/api.cc | 16 ++------ src/compiler/effect-control-linearizer.cc | 4 +- src/compiler/js-call-reducer.cc | 21 ---------- src/d8/d8-test.cc | 9 +---- .../compiler/fast-api-sequences-x64.js | 4 +- 6 files changed, 45 insertions(+), 47 deletions(-) diff --git a/include/v8-fast-api-calls.h b/include/v8-fast-api-calls.h index 48e485a6f1..22c4073837 100644 --- a/include/v8-fast-api-calls.h +++ b/include/v8-fast-api-calls.h @@ -299,10 +299,42 @@ class CTypeInfo { Flags flags_; }; +struct FastApiTypedArrayBase { + public: + // Returns the length in number of elements. + size_t V8_EXPORT length() const { return length_; } + // Checks whether the given index is within the bounds of the collection. + void V8_EXPORT ValidateIndex(size_t index) const; + + protected: + size_t length_ = 0; +}; + template -struct FastApiTypedArray { - T* data; // should include the typed array offset applied - size_t length; // length in number of elements +struct FastApiTypedArray : public FastApiTypedArrayBase { + public: + V8_INLINE T get(size_t index) const { +#ifdef DEBUG + ValidateIndex(index); +#endif // DEBUG + static_assert(offsetof(FastApiTypedArray, length_) < + offsetof(FastApiTypedArray, data_), + "length_ should be " + "stored in memory before data_, initializing the " + "FastApiTypedArray struct will fail."); + + T tmp; + memcpy(&tmp, reinterpret_cast(data_) + index, sizeof(T)); + return tmp; + } + + private: + // This pointer should include the typed array offset applied. + // It's not guaranteed that it's aligned to sizeof(T), it's only + // guaranteed that it's 4-byte aligned, so for 8-byte types we need to + // provide a special implementation for reading from it, which hides + // the possibly unaligned read in the `get` method. + void* data_; }; // Any TypedArray. It uses kTypedArrayBit with base type void diff --git a/src/api/api.cc b/src/api/api.cc index aae08a46e6..a8af304a53 100644 --- a/src/api/api.cc +++ b/src/api/api.cc @@ -10045,6 +10045,10 @@ const CTypeInfo& CFunctionInfo::ArgumentInfo(unsigned int index) const { return arg_info_[index]; } +void FastApiTypedArrayBase::ValidateIndex(size_t index) const { + DCHECK_LT(index, length_); +} + RegisterState::RegisterState() : pc(nullptr), sp(nullptr), fp(nullptr), lr(nullptr) {} RegisterState::~RegisterState() = default; @@ -10332,18 +10336,6 @@ bool ConvertDouble(double d) { } // namespace internal -bool CopyAndConvertArrayToCppBufferInt32(Local src, int32_t* dst, - uint32_t max_length) { - return CopyAndConvertArrayToCppBuffer<&v8::kTypeInfoInt32, int32_t>( - src, dst, max_length); -} - -bool CopyAndConvertArrayToCppBufferFloat64(Local src, double* dst, - uint32_t max_length) { - return CopyAndConvertArrayToCppBuffer<&v8::kTypeInfoFloat64, double>( - src, dst, max_length); -} - } // namespace v8 #undef TRACE_BS diff --git a/src/compiler/effect-control-linearizer.cc b/src/compiler/effect-control-linearizer.cc index 0cde0b9d00..d7a0ca62dd 100644 --- a/src/compiler/effect-control-linearizer.cc +++ b/src/compiler/effect-control-linearizer.cc @@ -5083,10 +5083,10 @@ Node* EffectControlLinearizer::AdaptFastCallTypedArrayArgument( __ Store(StoreRepresentation(MachineType::PointerRepresentation(), kNoWriteBarrier), - stack_slot, 0, data_ptr); + stack_slot, 0, length_in_bytes); __ Store(StoreRepresentation(MachineType::PointerRepresentation(), kNoWriteBarrier), - stack_slot, sizeof(uintptr_t), length_in_bytes); + stack_slot, sizeof(size_t), data_ptr); static_assert(sizeof(uintptr_t) == sizeof(size_t), "The buffer length can't " "fit the PointerRepresentation used to store it."); diff --git a/src/compiler/js-call-reducer.cc b/src/compiler/js-call-reducer.cc index bfa588fa37..41e5a4616b 100644 --- a/src/compiler/js-call-reducer.cc +++ b/src/compiler/js-call-reducer.cc @@ -3549,23 +3549,6 @@ bool Has64BitIntegerParamsInSignature(const CFunctionInfo* c_signature) { } // namespace #endif -namespace { -bool Has64BitTypedArraysInSignature(const CFunctionInfo* c_signature) { - for (unsigned int i = 0; i < c_signature->ArgumentCount(); ++i) { - if (c_signature->ArgumentInfo(i).GetSequenceType() != - CTypeInfo::SequenceType::kIsTypedArray) { - continue; - } - if (c_signature->ArgumentInfo(i).GetType() == CTypeInfo::Type::kInt64 || - c_signature->ArgumentInfo(i).GetType() == CTypeInfo::Type::kUint64 || - c_signature->ArgumentInfo(i).GetType() == CTypeInfo::Type::kFloat64) { - return true; - } - } - return false; -} -} // namespace - // Given a FunctionTemplateInfo, checks whether the fast API call can be // optimized, applying the initial step of the overload resolution algorithm: // Given an overload set function_template_info.c_signatures, and a list of @@ -3620,10 +3603,6 @@ FastApiCallFunctionVector CanOptimizeFastCall( optimize_to_fast_call = optimize_to_fast_call && !Has64BitIntegerParamsInSignature(c_signature); #endif - // TODO(mslekova): Add back support for 64-bit TA params when the API is - // changed to disallow raw access to unaligned data. - optimize_to_fast_call = - optimize_to_fast_call && !Has64BitTypedArraysInSignature(c_signature); if (optimize_to_fast_call) { result.push_back({functions[i], c_signature}); diff --git a/src/d8/d8-test.cc b/src/d8/d8-test.cc index 8bbdbe9b96..635a1f4514 100644 --- a/src/d8/d8-test.cc +++ b/src/d8/d8-test.cc @@ -206,14 +206,9 @@ class FastCApiObject { return 0; } - if (!typed_array_arg.data) { - options.fallback = 1; - return 0; - } - T sum = 0; - for (unsigned i = 0; i < typed_array_arg.length; ++i) { - sum += typed_array_arg.data[i]; + for (unsigned i = 0; i < typed_array_arg.length(); ++i) { + sum += typed_array_arg.get(i); } return static_cast(sum); } diff --git a/test/mjsunit/compiler/fast-api-sequences-x64.js b/test/mjsunit/compiler/fast-api-sequences-x64.js index a79ade6740..7bc8db4ec7 100644 --- a/test/mjsunit/compiler/fast-api-sequences-x64.js +++ b/test/mjsunit/compiler/fast-api-sequences-x64.js @@ -41,7 +41,7 @@ const max_safe_as_bigint = BigInt(Number.MAX_SAFE_INTEGER); typed_array); } const expected = Number(BigInt.asIntN(64, -42n + 1n + max_safe_as_bigint)); - ExpectSlowCall(int64_test, expected); + ExpectFastCall(int64_test, expected); })(); (function () { @@ -51,5 +51,5 @@ const max_safe_as_bigint = BigInt(Number.MAX_SAFE_INTEGER); typed_array); } const expected = Number(BigInt.asUintN(64, max_safe_as_bigint + 1n + 2n)); - ExpectSlowCall(uint64_test, expected); + ExpectFastCall(uint64_test, expected); })();