From 5131e66fa5dece8ca99093dc5573e22ca8b5d682 Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Tue, 24 Jun 2025 17:39:33 -0700 Subject: [PATCH] Optimize `napi_get_value_string_utf8` `napi_get_value_string_latin1` `napi_get_value_string_utf16` (#20612) --- src/bun.js/bindings/napi.cpp | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/src/bun.js/bindings/napi.cpp b/src/bun.js/bindings/napi.cpp index 3d5f0340ed..fcbe5c986f 100644 --- a/src/bun.js/bindings/napi.cpp +++ b/src/bun.js/bindings/napi.cpp @@ -2059,23 +2059,26 @@ struct BufferElement { template napi_status napi_get_value_string_any_encoding(napi_env env, napi_value napiValue, typename BufferElement::Type* buf, size_t bufsize, size_t* writtenPtr) { + NAPI_PREAMBLE(env); NAPI_CHECK_ARG(env, napiValue); JSValue jsValue = toJS(napiValue); NAPI_RETURN_EARLY_IF_FALSE(env, jsValue.isString(), napi_string_expected); Zig::GlobalObject* globalObject = toJS(env); - String view = jsValue.asCell()->getString(globalObject); - size_t length = view.length(); + JSString* jsString = jsValue.toString(globalObject); + NAPI_RETURN_IF_EXCEPTION(env); + const auto view = jsString->view(globalObject); + NAPI_RETURN_IF_EXCEPTION(env); if (buf == nullptr) { // they just want to know the length NAPI_CHECK_ARG(env, writtenPtr); switch (EncodeTo) { case NapiStringEncoding::utf8: - if (view.is8Bit()) { - *writtenPtr = Bun__encoding__byteLengthLatin1AsUTF8(view.span8().data(), length); + if (view->is8Bit()) { + *writtenPtr = Bun__encoding__byteLengthLatin1AsUTF8(view->span8().data(), view->length()); } else { - *writtenPtr = Bun__encoding__byteLengthUTF16AsUTF8(view.span16().data(), length); + *writtenPtr = Bun__encoding__byteLengthUTF16AsUTF8(view->span16().data(), view->length()); } break; case NapiStringEncoding::utf16le: @@ -2084,7 +2087,7 @@ napi_status napi_get_value_string_any_encoding(napi_env env, napi_value napiValu // if the string's encoding is the same as the destination encoding, this is trivially correct // if we are converting UTF-16 to Latin-1, then we do so by truncating each code unit, so the length is the same // if we are converting Latin-1 to UTF-16, then we do so by extending each code unit, so the length is also the same - *writtenPtr = length; + *writtenPtr = view->length(); break; } return napi_set_last_error(env, napi_ok); @@ -2108,19 +2111,22 @@ napi_status napi_get_value_string_any_encoding(napi_env env, napi_value napiValu // since we need to put a null terminator there ? 2 * (bufsize - 1) : bufsize - 1); - if (view.is8Bit()) { + if (view->is8Bit()) { + const auto span = view->span8(); if constexpr (EncodeTo == NapiStringEncoding::utf16le) { + // pass subslice to work around Bun__encoding__writeLatin1 asserting that the output has room - written = Bun__encoding__writeLatin1(view.span8().data(), - std::min(static_cast(view.span8().size()), bufsize), + written = Bun__encoding__writeLatin1(span.data(), + std::min(static_cast(span.size()), bufsize), writable_byte_slice.data(), writable_byte_slice.size(), static_cast(EncodeTo)); } else { - written = Bun__encoding__writeLatin1(view.span8().data(), view.length(), writable_byte_slice.data(), writable_byte_slice.size(), static_cast(EncodeTo)); + written = Bun__encoding__writeLatin1(span.data(), span.size(), writable_byte_slice.data(), writable_byte_slice.size(), static_cast(EncodeTo)); } } else { - written = Bun__encoding__writeUTF16(view.span16().data(), view.length(), writable_byte_slice.data(), writable_byte_slice.size(), static_cast(EncodeTo)); + const auto span = view->span16(); + written = Bun__encoding__writeUTF16(span.data(), span.size(), writable_byte_slice.data(), writable_byte_slice.size(), static_cast(EncodeTo)); } // convert bytes to code units