Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions NativeScript/ffi/jni/jsi/conversion/JsArgConverter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -453,7 +453,15 @@ bool JsArgConverter::ConvertJavaScriptArray(JsRuntime &rt, const JsValue &jsArr,
case 'I': {
arr = jenv.NewIntArray(arrLength);
std::vector<jint> ints(arrLength);
for (jsize i = 0; i < arrLength; i++) {
std::vector<double> numbers(arrLength);
size_t copied = 0;
bool bulk = jsArray.copyNumbers(rt, numbers.data(), (size_t) arrLength, &copied) &&
copied == (size_t) arrLength;
for (jsize i = 0; bulk && i < arrLength; i++) {
bulk = numbers[i] >= INT32_MIN && numbers[i] <= INT32_MAX;
ints[i] = (jint) numbers[i];
}
for (jsize i = 0; !bulk && i < arrLength; i++) {
ints[i] = (jint) js_util::get_int32(jsArray.getValueAtIndexBorrowed(rt, i));
}
jenv.SetIntArrayRegion((jintArray) arr, 0, arrLength, ints.data());
Expand All @@ -480,7 +488,10 @@ bool JsArgConverter::ConvertJavaScriptArray(JsRuntime &rt, const JsValue &jsArr,
case 'D': {
arr = jenv.NewDoubleArray(arrLength);
std::vector<jdouble> doubles(arrLength);
for (jsize i = 0; i < arrLength; i++) {
size_t copied = 0;
bool bulk = jsArray.copyNumbers(rt, doubles.data(), (size_t) arrLength, &copied) &&
copied == (size_t) arrLength;
for (jsize i = 0; !bulk && i < arrLength; i++) {
doubles[i] = (jdouble) js_util::get_number(jsArray.getValueAtIndexBorrowed(rt, i));
}
jenv.SetDoubleArrayRegion((jdoubleArray) arr, 0, arrLength, doubles.data());
Expand Down
16 changes: 14 additions & 2 deletions NativeScript/ffi/jni/napi/conversion/JsArgConverter.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "JsArgConverter.h"
#include "jsr_common.h"
#include "ObjectManager.h"
#include "JniSignatureParser.h"
#include "JsArgToArrayConverter.h"
Expand Down Expand Up @@ -616,7 +617,15 @@ bool JsArgConverter::ConvertJavaScriptArray(napi_env env, napi_value jsArr, int
case 'I': {
arr = jenv.NewIntArray(arrLength);
std::vector<jint> ints(arrLength);
for (uint32_t i = 0; i < arrLength; i++) {
std::vector<double> numbers(arrLength);
uint32_t copied = 0;
bool bulk = js_get_array_doubles(env, jsArr, numbers.data(), arrLength, &copied) == napi_ok &&
copied == arrLength;
for (uint32_t i = 0; bulk && i < arrLength; i++) {
bulk = numbers[i] >= INT32_MIN && numbers[i] <= INT32_MAX;
ints[i] = (jint) numbers[i];
}
for (uint32_t i = 0; !bulk && i < arrLength; i++) {
napi_value element;
NAPI_GUARD(napi_get_element(env, jsArr, i, &element)) {}
int32_t intValue;
Expand Down Expand Up @@ -655,7 +664,10 @@ bool JsArgConverter::ConvertJavaScriptArray(napi_env env, napi_value jsArr, int
case 'D': {
arr = jenv.NewDoubleArray(arrLength);
std::vector<jdouble> doubles(arrLength);
for (uint32_t i = 0; i < arrLength; i++) {
uint32_t copied = 0;
bool bulk = js_get_array_doubles(env, jsArr, doubles.data(), arrLength, &copied) == napi_ok &&
copied == arrLength;
for (uint32_t i = 0; !bulk && i < arrLength; i++) {
napi_value element;
NAPI_GUARD(napi_get_element(env, jsArr, i, &element)) {}
double doubleValue;
Expand Down
14 changes: 14 additions & 0 deletions NativeScript/jsi/hermes/HermesRuntime.h
Original file line number Diff line number Diff line change
Expand Up @@ -689,6 +689,20 @@ class Array : public Object {
Value getValueAtIndex(Runtime& runtime, size_t index) const;

// See Object::getPropertyBorrowed.
// Copies the leading numeric elements into `out`. Returns false when an element is not a
// number, and the caller falls back to per-element reads.
bool copyNumbers(Runtime& runtime, double* out, size_t capacity, size_t* length) const {
size_t count = size(runtime);
if (count > capacity) count = capacity;
for (size_t i = 0; i < count; i++) {
Value element = getValueAtIndexBorrowed(runtime, i);
if (!element.isNumber()) return false;
out[i] = element.getNumber();
}
*length = count;
return true;
}

Value getValueAtIndexBorrowed(Runtime& runtime, size_t index) const {
return getValueAtIndex(runtime, index);
}
Expand Down
14 changes: 14 additions & 0 deletions NativeScript/jsi/jsc/JSCRuntime.h
Original file line number Diff line number Diff line change
Expand Up @@ -1142,6 +1142,20 @@ class Array : public Object {
}

// See Object::getPropertyBorrowed.
// Copies the leading numeric elements into `out`. Returns false when an element is not a
// number, and the caller falls back to per-element reads.
bool copyNumbers(Runtime& runtime, double* out, size_t capacity, size_t* length) const {
size_t count = size(runtime);
if (count > capacity) count = capacity;
for (size_t i = 0; i < count; i++) {
Value element = getValueAtIndexBorrowed(runtime, i);
if (!element.isNumber()) return false;
out[i] = element.getNumber();
}
*length = count;
return true;
}

Value getValueAtIndexBorrowed(Runtime& runtime, size_t index) const {
return getValueAtIndex(runtime, index);
}
Expand Down
14 changes: 14 additions & 0 deletions NativeScript/jsi/quickjs/QuickJSRuntime.h
Original file line number Diff line number Diff line change
Expand Up @@ -1138,6 +1138,20 @@ class Array : public Object {
return length.isNumber() ? static_cast<size_t>(std::max<double>(0, length.getNumber())) : 0;
}
// See Object::getPropertyBorrowed.
// Copies the leading numeric elements into `out`. Returns false when an element is not a
// number, and the caller falls back to per-element reads.
bool copyNumbers(Runtime& runtime, double* out, size_t capacity, size_t* length) const {
size_t count = size(runtime);
if (count > capacity) count = capacity;
for (size_t i = 0; i < count; i++) {
Value element = getValueAtIndexBorrowed(runtime, i);
if (!element.isNumber()) return false;
out[i] = element.getNumber();
}
*length = count;
return true;
}

Value getValueAtIndexBorrowed(Runtime& runtime, size_t index) const {
return getValueAtIndex(runtime, index);
}
Expand Down
32 changes: 32 additions & 0 deletions NativeScript/jsi/v8/V8Runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -1281,6 +1281,38 @@ class Array : public Object {
}

// See Object::getPropertyBorrowed for the lifetime contract.
// Copies the leading numeric elements into `out`. Returns false when an element is not a
// number, and the caller falls back to per-element reads. Iterate walks a packed backing
// store without a handle or exception check per element.
bool copyNumbers(Runtime& runtime, double* out, size_t capacity, size_t* length) const {
v8::Local<v8::Array> array = local(runtime).As<v8::Array>();
size_t count = static_cast<size_t>(array->Length());
if (count > capacity) count = capacity;
struct State {
double* out;
size_t count;
size_t written;
bool numbersOnly;
} state{out, count, 0, true};
v8::Maybe<void> result = array->Iterate(
runtime.context(),
[](uint32_t index, v8::Local<v8::Value> element, void* data) {
auto* s = static_cast<State*>(data);
if (index >= s->count) return v8::Array::CallbackResult::kBreak;
if (!element->IsNumber()) {
s->numbersOnly = false;
return v8::Array::CallbackResult::kBreak;
}
s->out[index] = element.As<v8::Number>()->Value();
s->written++;
return v8::Array::CallbackResult::kContinue;
},
&state);
if (result.IsNothing() || !state.numbersOnly || state.written != count) return false;
*length = count;
return true;
}

Value getValueAtIndexBorrowed(Runtime& runtime, size_t index) const {
v8::TryCatch tryCatch(runtime.isolate());
v8::Local<v8::Value> result;
Expand Down
5 changes: 5 additions & 0 deletions NativeScript/napi/common/jsr_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ napi_status js_execute_pending_jobs(napi_env env);

napi_status js_get_engine_ptr(napi_env env, int64_t *engine_ptr);
napi_status js_adjust_external_memory(napi_env env, int64_t changeInBytes, int64_t* externalMemory);

// Copies the leading elements of a packed numeric JS array into `out`. Returns a failure
// status when an element is not a number, and the caller falls back to per-element reads.
napi_status js_get_array_doubles(napi_env env, napi_value array, double* out, uint32_t capacity,
uint32_t* length);
napi_status js_cache_script(napi_env env, const char *source, const char *file);
napi_status js_run_cached_script(napi_env env, const char * file, napi_value script, void* cache, napi_value *result);

Expand Down
16 changes: 16 additions & 0 deletions NativeScript/napi/hermes/jsr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -450,3 +450,19 @@ extern "C" napi_status jsr_drain_microtasks(napi_env env,

return napi_ok;
}

napi_status js_get_array_doubles(napi_env env, napi_value array, double* out, uint32_t capacity,
uint32_t* length) {
bool isArray = false;
if (napi_is_array(env, array, &isArray) != napi_ok || !isArray) return napi_array_expected;
uint32_t count = 0;
if (napi_get_array_length(env, array, &count) != napi_ok) return napi_array_expected;
if (count > capacity) count = capacity;
for (uint32_t i = 0; i < count; i++) {
napi_value element;
if (napi_get_element(env, array, i, &element) != napi_ok) return napi_generic_failure;
if (napi_get_value_double(env, element, &out[i]) != napi_ok) return napi_number_expected;
}
*length = count;
return napi_ok;
}
16 changes: 16 additions & 0 deletions NativeScript/napi/jsc/jsr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -370,3 +370,19 @@ napi_status js_get_runtime_version(napi_env env, napi_value* version) {

return napi_ok;
}

napi_status js_get_array_doubles(napi_env env, napi_value array, double* out, uint32_t capacity,
uint32_t* length) {
bool isArray = false;
if (napi_is_array(env, array, &isArray) != napi_ok || !isArray) return napi_array_expected;
uint32_t count = 0;
if (napi_get_array_length(env, array, &count) != napi_ok) return napi_array_expected;
if (count > capacity) count = capacity;
for (uint32_t i = 0; i < count; i++) {
napi_value element;
if (napi_get_element(env, array, i, &element) != napi_ok) return napi_generic_failure;
if (napi_get_value_double(env, element, &out[i]) != napi_ok) return napi_number_expected;
}
*length = count;
return napi_ok;
}
16 changes: 16 additions & 0 deletions NativeScript/napi/primjs/jsr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -177,3 +177,19 @@ napi_status js_get_runtime_version(napi_env env, napi_value *version) {
napi_create_string_utf8(env, "PrimJS", NAPI_AUTO_LENGTH, version);
return napi_ok;
}

napi_status js_get_array_doubles(napi_env env, napi_value array, double* out, uint32_t capacity,
uint32_t* length) {
bool isArray = false;
if (napi_is_array(env, array, &isArray) != napi_ok || !isArray) return napi_array_expected;
uint32_t count = 0;
if (napi_get_array_length(env, array, &count) != napi_ok) return napi_array_expected;
if (count > capacity) count = capacity;
for (uint32_t i = 0; i < count; i++) {
napi_value element;
if (napi_get_element(env, array, i, &element) != napi_ok) return napi_generic_failure;
if (napi_get_value_double(env, element, &out[i]) != napi_ok) return napi_number_expected;
}
*length = count;
return napi_ok;
}
16 changes: 16 additions & 0 deletions NativeScript/napi/quickjs/jsr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -148,3 +148,19 @@ napi_status js_get_runtime_version(napi_env env, napi_value *version) {

return napi_ok;
}

napi_status js_get_array_doubles(napi_env env, napi_value array, double* out, uint32_t capacity,
uint32_t* length) {
bool isArray = false;
if (napi_is_array(env, array, &isArray) != napi_ok || !isArray) return napi_array_expected;
uint32_t count = 0;
if (napi_get_array_length(env, array, &count) != napi_ok) return napi_array_expected;
if (count > capacity) count = capacity;
for (uint32_t i = 0; i < count; i++) {
napi_value element;
if (napi_get_element(env, array, i, &element) != napi_ok) return napi_generic_failure;
if (napi_get_value_double(env, element, &out[i]) != napi_ok) return napi_number_expected;
}
*length = count;
return napi_ok;
}
35 changes: 35 additions & 0 deletions NativeScript/napi/v8/jsr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -583,3 +583,38 @@ napi_status js_get_runtime_version(napi_env env, napi_value* version) {

return napi_ok;
}

napi_status js_get_array_doubles(napi_env env, napi_value array, double* out, uint32_t capacity,
uint32_t* length) {
v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(array);
if (!value->IsArray()) return napi_array_expected;
v8::Local<v8::Array> jsArray = value.As<v8::Array>();
uint32_t count = jsArray->Length();
if (count > capacity) count = capacity;

struct State {
double* out;
uint32_t count;
uint32_t written;
bool numbersOnly;
} state{out, count, 0, true};

v8::Maybe<void> result = jsArray->Iterate(
env->context(),
[](uint32_t index, v8::Local<v8::Value> element, void* data) {
auto* s = static_cast<State*>(data);
if (index >= s->count) return v8::Array::CallbackResult::kBreak;
if (!element->IsNumber()) {
s->numbersOnly = false;
return v8::Array::CallbackResult::kBreak;
}
s->out[index] = element.As<v8::Number>()->Value();
s->written++;
return v8::Array::CallbackResult::kContinue;
},
&state);
if (result.IsNothing()) return napi_generic_failure;
if (!state.numbersOnly || state.written != count) return napi_number_expected;
*length = count;
return napi_ok;
}
Loading