From 2643801d9d6cfe5528d92fd7dd83d8ba73e574a3 Mon Sep 17 00:00:00 2001 From: Anthony Tuininga Date: Mon, 4 Mar 2019 15:02:27 -0700 Subject: [PATCH] n-api: improve performance creating strings Improve performance creating strings using N-API by ensuring that the strings are not internalized. Added test cases for latin-1 and utf-16 strings. PR-URL: https://github.com/nodejs/node/pull/26439 Fixes: https://github.com/nodejs/node/issues/26437 Reviewed-By: Anna Henningsen Reviewed-By: Michael Dawson Reviewed-By: James M Snell --- src/node_api.cc | 25 ++++++++++++++----- test/addons-napi/test_string/test.js | 8 +++++++ test/addons-napi/test_string/test_string.c | 28 ++++++++++++++++++++++ 3 files changed, 55 insertions(+), 6 deletions(-) diff --git a/src/node_api.cc b/src/node_api.cc index a13fdcdead4c7c..0618b3f7bf37ec 100644 --- a/src/node_api.cc +++ b/src/node_api.cc @@ -2055,12 +2055,15 @@ napi_status napi_create_string_latin1(napi_env env, napi_value* result) { CHECK_ENV(env); CHECK_ARG(env, result); + RETURN_STATUS_IF_FALSE(env, + (length == NAPI_AUTO_LENGTH) || length <= INT_MAX, + napi_invalid_arg); auto isolate = env->isolate; auto str_maybe = v8::String::NewFromOneByte(isolate, reinterpret_cast(str), - v8::NewStringType::kInternalized, + v8::NewStringType::kNormal, length); CHECK_MAYBE_EMPTY(env, str_maybe, napi_generic_failure); @@ -2074,11 +2077,18 @@ napi_status napi_create_string_utf8(napi_env env, napi_value* result) { CHECK_ENV(env); CHECK_ARG(env, result); + RETURN_STATUS_IF_FALSE(env, + (length == NAPI_AUTO_LENGTH) || length <= INT_MAX, + napi_invalid_arg); - v8::Local s; - CHECK_NEW_FROM_UTF8_LEN(env, s, str, length); - - *result = v8impl::JsValueFromV8LocalValue(s); + auto isolate = env->isolate; + auto str_maybe = + v8::String::NewFromUtf8(isolate, + str, + v8::NewStringType::kNormal, + static_cast(length)); + CHECK_MAYBE_EMPTY(env, str_maybe, napi_generic_failure); + *result = v8impl::JsValueFromV8LocalValue(str_maybe.ToLocalChecked()); return napi_clear_last_error(env); } @@ -2088,12 +2098,15 @@ napi_status napi_create_string_utf16(napi_env env, napi_value* result) { CHECK_ENV(env); CHECK_ARG(env, result); + RETURN_STATUS_IF_FALSE(env, + (length == NAPI_AUTO_LENGTH) || length <= INT_MAX, + napi_invalid_arg); auto isolate = env->isolate; auto str_maybe = v8::String::NewFromTwoByte(isolate, reinterpret_cast(str), - v8::NewStringType::kInternalized, + v8::NewStringType::kNormal, length); CHECK_MAYBE_EMPTY(env, str_maybe, napi_generic_failure); diff --git a/test/addons-napi/test_string/test.js b/test/addons-napi/test_string/test.js index 5ce3d739c7a941..86fdc1640602bc 100644 --- a/test/addons-napi/test_string/test.js +++ b/test/addons-napi/test_string/test.js @@ -73,3 +73,11 @@ assert.strictEqual(test_string.Utf8Length(str6), 14); assert.throws(() => { test_string.TestLargeUtf8(); }, /^Error: Invalid argument$/); + +assert.throws(() => { + test_string.TestLargeLatin1(); +}, /^Error: Invalid argument$/); + +assert.throws(() => { + test_string.TestLargeUtf16(); +}, /^Error: Invalid argument$/); diff --git a/test/addons-napi/test_string/test_string.c b/test/addons-napi/test_string/test_string.c index 4e6da7bf86849f..07237d17471561 100644 --- a/test/addons-napi/test_string/test_string.c +++ b/test/addons-napi/test_string/test_string.c @@ -216,6 +216,32 @@ static napi_value TestLargeUtf8(napi_env env, napi_callback_info info) { return output; } +static napi_value TestLargeLatin1(napi_env env, napi_callback_info info) { + napi_value output; + if (SIZE_MAX > INT_MAX) { + NAPI_CALL(env, napi_create_string_latin1(env, "", ((size_t)INT_MAX) + 1, &output)); + } else { + // just throw the expected error as there is nothing to test + // in this case since we can't overflow + NAPI_CALL(env, napi_throw_error(env, NULL, "Invalid argument")); + } + + return output; +} + +static napi_value TestLargeUtf16(napi_env env, napi_callback_info info) { + napi_value output; + if (SIZE_MAX > INT_MAX) { + NAPI_CALL(env, napi_create_string_utf16(env, "", ((size_t)INT_MAX) + 1, &output)); + } else { + // just throw the expected error as there is nothing to test + // in this case since we can't overflow + NAPI_CALL(env, napi_throw_error(env, NULL, "Invalid argument")); + } + + return output; +} + static napi_value Init(napi_env env, napi_value exports) { napi_property_descriptor properties[] = { DECLARE_NAPI_PROPERTY("TestLatin1", TestLatin1), @@ -227,6 +253,8 @@ static napi_value Init(napi_env env, napi_value exports) { DECLARE_NAPI_PROPERTY("Utf16Length", Utf16Length), DECLARE_NAPI_PROPERTY("Utf8Length", Utf8Length), DECLARE_NAPI_PROPERTY("TestLargeUtf8", TestLargeUtf8), + DECLARE_NAPI_PROPERTY("TestLargeLatin1", TestLargeLatin1), + DECLARE_NAPI_PROPERTY("TestLargeUtf16", TestLargeUtf16), }; NAPI_CALL(env, napi_define_properties(