38
38
#include < cstring>
39
39
#include < climits>
40
40
41
+ #if defined(__aarch64__) || defined(_M_ARM64)
42
+ #define NODE_HAS_SIMD_NEON 1
43
+ #endif
44
+
45
+ #if NODE_HAS_SIMD_NEON
46
+ #include < arm_neon.h>
47
+ #endif
48
+
41
49
#define THROW_AND_RETURN_UNLESS_BUFFER (env, obj ) \
42
50
THROW_AND_RETURN_IF_NOT_BUFFER (env, obj, " argument" ) \
43
51
@@ -741,6 +749,38 @@ void SlowByteLengthUtf8(const FunctionCallbackInfo<Value>& args) {
741
749
args.GetReturnValue ().Set (args[0 ].As <String>()->Utf8Length (env->isolate ()));
742
750
}
743
751
752
+ #if NODE_HAS_SIMD_NEON
753
+ uint32_t FastByteLengthUtf8 (Local<Value> receiver,
754
+ const v8::FastOneByteString& source) {
755
+ uint32_t answer{0 };
756
+ const auto data = reinterpret_cast <const uint8_t *>(source.data );
757
+ const uint8x16_t mask = vdupq_n_u8 (0x80 );
758
+ uint8x16_t result_vector = vdupq_n_u8 (0 );
759
+ size_t i = 0 ;
760
+
761
+ for (; i < source.length ; i += 16 ) {
762
+ // load 16 bytes from data
763
+ uint8x16_t values = vld1q_u8 (data + i);
764
+
765
+ // extract the high bits using 0x80 mask
766
+ uint8x16_t high_bits = vcgeq_u8 (values, mask);
767
+
768
+ // accumulate the high bits to result_vector
769
+ result_vector = vqaddq_u8 (result_vector, high_bits);
770
+ }
771
+
772
+ // sum the elements in the result_vector
773
+ uint64x2_t sum64 = vpaddlq_u32 (vpaddlq_u16 (vpaddlq_u8 (result_vector)));
774
+
775
+ answer = vgetq_lane_u64 (sum64, 0 ) + vgetq_lane_u64 (sum64, 1 );
776
+
777
+ for (; i < source.length ; ++i) {
778
+ answer += (data[i] >> 7 );
779
+ }
780
+
781
+ return answer + source.length ;
782
+ }
783
+ #else
744
784
uint32_t FastByteLengthUtf8 (Local<Value> receiver,
745
785
const v8::FastOneByteString& source) {
746
786
uint32_t result = 0 ;
@@ -752,6 +792,7 @@ uint32_t FastByteLengthUtf8(Local<Value> receiver,
752
792
result += length;
753
793
return result;
754
794
}
795
+ #endif
755
796
756
797
static v8::CFunction fast_byte_length_utf8 (
757
798
v8::CFunction::Make (FastByteLengthUtf8));
0 commit comments