Skip to content

Commit

Permalink
src: implement v8 array iteration using the new callback-based API
Browse files Browse the repository at this point in the history
Using this to iterate over an array can be faster than calling
Array::Get repeatedly. Local experiment shows that this is faster
once the array size is bigger than 2.

PR-URL: nodejs#51758
Reviewed-By: Yagiz Nizipli <yagiz.nizipli@sentry.io>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
  • Loading branch information
joyeecheung authored and rdw-msft committed Mar 26, 2024
1 parent 9c640f7 commit 49fa4a8
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 0 deletions.
23 changes: 23 additions & 0 deletions src/util-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,29 @@ inline char* UncheckedCalloc(size_t n) { return UncheckedCalloc<char>(n); }
// headers than we really need to.
void ThrowErrStringTooLong(v8::Isolate* isolate);

struct ArrayIterationData {
std::vector<v8::Global<v8::Value>>* out;
v8::Isolate* isolate = nullptr;
};

inline v8::Array::CallbackResult PushItemToVector(uint32_t index,
v8::Local<v8::Value> element,
void* data) {
auto vec = static_cast<ArrayIterationData*>(data)->out;
auto isolate = static_cast<ArrayIterationData*>(data)->isolate;
vec->push_back(v8::Global<v8::Value>(isolate, element));
return v8::Array::CallbackResult::kContinue;
}

v8::Maybe<void> FromV8Array(v8::Local<v8::Context> context,
v8::Local<v8::Array> js_array,
std::vector<v8::Global<v8::Value>>* out) {
uint32_t count = js_array->Length();
out->reserve(count);
ArrayIterationData data{out, context->GetIsolate()};
return js_array->Iterate(context, PushItemToVector, &data);
}

v8::MaybeLocal<v8::Value> ToV8Value(v8::Local<v8::Context> context,
std::string_view str,
v8::Isolate* isolate) {
Expand Down
10 changes: 10 additions & 0 deletions src/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -697,6 +697,16 @@ struct FunctionDeleter {
template <typename T, void (*function)(T*)>
using DeleteFnPtr = typename FunctionDeleter<T, function>::Pointer;

// Convert a v8::Array into an std::vector using the callback-based API.
// This can be faster than calling Array::Get() repeatedly when the array
// has more than 2 entries.
// Note that iterating over an array in C++ and performing operations on each
// element in a C++ loop is still slower than iterating over the array in JS
// and calling into native in the JS loop repeatedly on each element,
// as of V8 11.9.
inline v8::Maybe<void> FromV8Array(v8::Local<v8::Context> context,
v8::Local<v8::Array> js_array,
std::vector<v8::Global<v8::Value>>* out);
std::vector<std::string_view> SplitString(const std::string_view in,
const std::string_view delim);

Expand Down

0 comments on commit 49fa4a8

Please sign in to comment.