[fastcall] Type-specialize CopyAndConvertArrayToCppBuffer

Rename CopyAndConvertArrayToCppBuffer as
TryCopyAndConvertArrayToCppBuffer and implement type specialization for
int32_t and double in order to speed up V8 bindings with sequences.

This API is used by Blink code, for example see
https://chromium-review.googlesource.com/c/chromium/src/+/3027405.

Bug: v8:11739
Change-Id: I026a7f5e7833fb1afcc2ea9c296b66c7f733cbb1
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3036407
Commit-Queue: Paolo Severini <paolosev@microsoft.com>
Reviewed-by: Camillo Bruni <cbruni@chromium.org>
Reviewed-by: Maya Lekova <mslekova@chromium.org>
Cr-Commit-Position: refs/heads/master@{#76016}
This commit is contained in:
Paolo Severini 2021-07-23 11:29:30 -07:00 committed by V8 LUCI CQ
parent 3a44f269c5
commit 530fd795a9
9 changed files with 73 additions and 8 deletions

View File

@ -225,8 +225,9 @@
#include <tuple>
#include <type_traits>
#include "v8.h" // NOLINT(build/include_directory)
#include "v8config.h" // NOLINT(build/include_directory)
#include "v8-internal.h" // NOLINT(build/include_directory)
#include "v8.h" // NOLINT(build/include_directory)
#include "v8config.h" // NOLINT(build/include_directory)
namespace v8 {
@ -770,6 +771,10 @@ CFunction CFunction::ArgUnwrap<R (*)(Args...)>::Make(R (*func)(Args...)) {
using CFunctionBuilder = internal::CFunctionBuilder;
static constexpr CTypeInfo kTypeInfoInt32 = CTypeInfo(CTypeInfo::Type::kInt32);
static constexpr CTypeInfo kTypeInfoFloat64 =
CTypeInfo(CTypeInfo::Type::kFloat64);
/**
* Copies the contents of this JavaScript array to a C++ buffer with
* a given max_length. A CTypeInfo is passed as an argument,
@ -783,8 +788,20 @@ using CFunctionBuilder = internal::CFunctionBuilder;
* returns true on success. `type_info` will be used for conversions.
*/
template <const CTypeInfo* type_info, typename T>
bool CopyAndConvertArrayToCppBuffer(Local<Array> src, T* dst,
uint32_t max_length);
bool V8_EXPORT TryCopyAndConvertArrayToCppBuffer(Local<Array> src, T* dst,
uint32_t max_length);
template <>
inline bool TryCopyAndConvertArrayToCppBuffer<&kTypeInfoInt32, int32_t>(
Local<Array> src, int32_t* dst, uint32_t max_length) {
return CopyAndConvertArrayToCppBufferInt32(src, dst, max_length);
}
template <>
inline bool TryCopyAndConvertArrayToCppBuffer<&kTypeInfoFloat64, double>(
Local<Array> src, double* dst, uint32_t max_length) {
return CopyAndConvertArrayToCppBufferFloat64(src, dst, max_length);
}
} // namespace v8

View File

@ -15,9 +15,12 @@
namespace v8 {
class Array;
class Context;
class Data;
class Isolate;
template <typename T>
class Local;
namespace internal {
@ -505,6 +508,15 @@ V8_INLINE void PerformCastCheck(T* data) {
class BackingStoreBase {};
} // namespace internal
V8_EXPORT bool CopyAndConvertArrayToCppBufferInt32(Local<Array> src,
int32_t* dst,
uint32_t max_length);
V8_EXPORT bool CopyAndConvertArrayToCppBufferFloat64(Local<Array> src,
double* dst,
uint32_t max_length);
} // namespace v8
#endif // INCLUDE_V8_INTERNAL_H_

View File

@ -9,6 +9,7 @@
#include "src/api/api.h"
#include "src/execution/interrupts-scope.h"
#include "src/execution/microtask-queue.h"
#include "src/execution/protectors.h"
#include "src/handles/handles-inl.h"
#include "src/heap/heap-inl.h"
#include "src/objects/foreign-inl.h"
@ -279,6 +280,10 @@ bool CopyAndConvertArrayToCppBuffer(Local<Array> src, T* dst,
i::DisallowGarbageCollection no_gc;
i::JSArray obj = *reinterpret_cast<i::JSArray*>(*src);
if (obj.IterationHasObservableEffects()) {
// The array has a custom iterator.
return false;
}
i::FixedArrayBase elements = obj.elements();
switch (obj.GetElementsKind()) {
@ -294,6 +299,13 @@ bool CopyAndConvertArrayToCppBuffer(Local<Array> src, T* dst,
}
}
template <const CTypeInfo* type_info, typename T>
inline bool V8_EXPORT TryCopyAndConvertArrayToCppBuffer(Local<Array> src,
T* dst,
uint32_t max_length) {
return CopyAndConvertArrayToCppBuffer<type_info, T>(src, dst, max_length);
}
namespace internal {
Handle<Context> HandleScopeImplementer::LastEnteredContext() {

View File

@ -10315,6 +10315,19 @@ bool ConvertDouble(double d) {
#undef CALLBACK_SETTER
} // namespace internal
bool CopyAndConvertArrayToCppBufferInt32(Local<Array> src, int32_t* dst,
uint32_t max_length) {
return CopyAndConvertArrayToCppBuffer<&v8::kTypeInfoInt32, int32_t>(
src, dst, max_length);
}
bool CopyAndConvertArrayToCppBufferFloat64(Local<Array> src, double* dst,
uint32_t max_length) {
return CopyAndConvertArrayToCppBuffer<&v8::kTypeInfoFloat64, double>(
src, dst, max_length);
}
} // namespace v8
#undef TRACE_BS

View File

@ -119,8 +119,8 @@ class FastCApiObject {
}
Type buffer[1024];
bool result =
CopyAndConvertArrayToCppBuffer<&type_info, Type>(seq_arg, buffer, 1024);
bool result = TryCopyAndConvertArrayToCppBuffer<&type_info, Type>(
seq_arg, buffer, 1024);
if (!result) {
options.fallback = 1;
return 0;

View File

@ -1767,9 +1767,14 @@ bool Object::IterationHasObservableEffects() {
#endif
// Check that we have the original ArrayPrototype.
i::HandleScope handle_scope(isolate);
i::Handle<i::Context> context;
if (!array.GetCreationContext().ToHandle(&context)) return false;
if (!array.map().prototype().IsJSObject()) return true;
JSObject array_proto = JSObject::cast(array.map().prototype());
if (!isolate->is_initial_array_prototype(array_proto)) return true;
auto initial_array_prototype =
context->native_context().initial_array_prototype();
if (initial_array_prototype != array_proto) return true;
// Check that the ArrayPrototype hasn't been modified in a way that would
// affect iteration.

View File

@ -592,7 +592,7 @@ class Object : public TaggedImpl<HeapObjectReferenceType::STRONG, Address> {
// Returns true if the result of iterating over the object is the same
// (including observable effects) as simply accessing the properties between 0
// and length.
bool IterationHasObservableEffects();
V8_EXPORT_PRIVATE bool IterationHasObservableEffects();
// TC39 "Dynamic Code Brand Checks"
bool IsCodeLike(Isolate* isolate) const;

View File

@ -11,6 +11,9 @@
// The test relies on optimizing/deoptimizing at predictable moments, so
// it's not suitable for deoptimization fuzzing.
// Flags: --deopt-every-n-times=0
// The test relies on TryCopyAndConvertArrayToCppBuffer that fails with
// --force-slow-path.
// Flags: --no-force-slow-path
d8.file.execute('test/mjsunit/compiler/fast-api-helpers.js');

View File

@ -11,6 +11,9 @@
// The test relies on optimizing/deoptimizing at predictable moments, so
// it's not suitable for deoptimization fuzzing.
// Flags: --deopt-every-n-times=0
// The test relies on TryCopyAndConvertArrayToCppBuffer that fails with
// --force-slow-path.
// Flags: --no-force-slow-path
d8.file.execute('test/mjsunit/compiler/fast-api-helpers.js');