Skip to content

Commit df9f162

Browse files
joyeecheungrefack
authored andcommitted
src: initialize ICU version in per_process::metadata.versions
Instead of - Initialize the ICU versions in JS land after consulting internalBinding('config').hasIntl - Joining the version keys in C++ - Splitting the keys in JS and call into C++ again to get the value for each of the keys Do: - Guard the initialization code behind `NODE_HAVE_I18N_SUPPORT` - Do the initialization in C++ right after ICU data is loaded - Initialize each version directly using ICU functions/constants, and put them in per_process::metadata.versions. These will be copied into `process.versions` naturally later. This way, the initialization of the versions won't be called in worker threads again. PR-URL: nodejs#25115 Reviewed-By: Steven R Loomis <[email protected]> Reviewed-By: Richard Lau <[email protected]> Reviewed-By: Minwoo Jung <[email protected]> Reviewed-By: James M Snell <[email protected]>
1 parent d522b1e commit df9f162

File tree

5 files changed

+61
-85
lines changed

5 files changed

+61
-85
lines changed

lib/internal/bootstrap/node.js

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,6 @@ function startup() {
3838
// Do this good and early, since it handles errors.
3939
setupProcessFatal();
4040

41-
setupProcessICUVersions();
42-
4341
setupGlobalVariables();
4442

4543
// Bootstrappers for all threads, including worker threads and main thread
@@ -638,25 +636,6 @@ function setupProcessFatal() {
638636
};
639637
}
640638

641-
function setupProcessICUVersions() {
642-
const icu = internalBinding('config').hasIntl ?
643-
internalBinding('icu') : undefined;
644-
if (!icu) return; // no Intl/ICU: nothing to add here.
645-
// With no argument, getVersion() returns a comma separated list
646-
// of possible types.
647-
const versionTypes = icu.getVersion().split(',');
648-
649-
for (var n = 0; n < versionTypes.length; n++) {
650-
const name = versionTypes[n];
651-
const version = icu.getVersion(name);
652-
Object.defineProperty(process.versions, name, {
653-
writable: false,
654-
enumerable: true,
655-
value: version
656-
});
657-
}
658-
}
659-
660639
function wrapForBreakOnFirstLine(source) {
661640
if (!process._breakFirstLine)
662641
return source;

src/node.cc

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -877,7 +877,10 @@ void SetupProcessObject(Environment* env,
877877
READONLY_PROPERTY(process, "versions", versions);
878878

879879
#define V(key) \
880-
READONLY_STRING_PROPERTY(versions, #key, per_process::metadata.versions.key);
880+
if (!per_process::metadata.versions.key.empty()) { \
881+
READONLY_STRING_PROPERTY( \
882+
versions, #key, per_process::metadata.versions.key); \
883+
}
881884
NODE_VERSIONS_KEYS(V)
882885
#undef V
883886

@@ -1664,6 +1667,7 @@ void Init(std::vector<std::string>* argv,
16641667
argv->at(0).c_str());
16651668
exit(9);
16661669
}
1670+
per_process::metadata.versions.InitializeIntlVersions();
16671671
#endif
16681672

16691673
// We should set node_is_initialized here instead of in node::Start,

src/node_i18n.cc

Lines changed: 0 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -510,67 +510,6 @@ void ICUErrorName(const FunctionCallbackInfo<Value>& args) {
510510
NewStringType::kNormal).ToLocalChecked());
511511
}
512512

513-
#define TYPE_ICU "icu"
514-
#define TYPE_UNICODE "unicode"
515-
#define TYPE_CLDR "cldr"
516-
#define TYPE_TZ "tz"
517-
518-
/**
519-
* This is the workhorse function that deals with the actual version info.
520-
* Get an ICU version.
521-
* @param type the type of version to get. One of VERSION_TYPES
522-
* @param buf optional buffer for result
523-
* @param status ICU error status. If failure, assume result is undefined.
524-
* @return version number, or NULL. May or may not be buf.
525-
*/
526-
const char* GetVersion(const char* type,
527-
char buf[U_MAX_VERSION_STRING_LENGTH],
528-
UErrorCode* status) {
529-
if (!strcmp(type, TYPE_ICU)) {
530-
return U_ICU_VERSION;
531-
} else if (!strcmp(type, TYPE_UNICODE)) {
532-
return U_UNICODE_VERSION;
533-
} else if (!strcmp(type, TYPE_TZ)) {
534-
return icu::TimeZone::getTZDataVersion(*status);
535-
} else if (!strcmp(type, TYPE_CLDR)) {
536-
UVersionInfo versionArray;
537-
ulocdata_getCLDRVersion(versionArray, status);
538-
if (U_SUCCESS(*status)) {
539-
u_versionToString(versionArray, buf);
540-
return buf;
541-
}
542-
}
543-
// Fall through - unknown type or error case
544-
return nullptr;
545-
}
546-
547-
void GetVersion(const FunctionCallbackInfo<Value>& args) {
548-
Environment* env = Environment::GetCurrent(args);
549-
if ( args.Length() == 0 ) {
550-
// With no args - return a comma-separated list of allowed values
551-
args.GetReturnValue().Set(
552-
String::NewFromUtf8(env->isolate(),
553-
TYPE_ICU ","
554-
TYPE_UNICODE ","
555-
TYPE_CLDR ","
556-
TYPE_TZ, NewStringType::kNormal).ToLocalChecked());
557-
} else {
558-
CHECK_GE(args.Length(), 1);
559-
CHECK(args[0]->IsString());
560-
Utf8Value val(env->isolate(), args[0]);
561-
UErrorCode status = U_ZERO_ERROR;
562-
char buf[U_MAX_VERSION_STRING_LENGTH] = ""; // Possible output buffer.
563-
const char* versionString = GetVersion(*val, buf, &status);
564-
565-
if (U_SUCCESS(status) && versionString) {
566-
// Success.
567-
args.GetReturnValue().Set(
568-
String::NewFromUtf8(env->isolate(),
569-
versionString, NewStringType::kNormal).ToLocalChecked());
570-
}
571-
}
572-
}
573-
574513
} // anonymous namespace
575514

576515
bool InitializeICUDirectory(const std::string& path) {
@@ -868,7 +807,6 @@ void Initialize(Local<Object> target,
868807
env->SetMethod(target, "toUnicode", ToUnicode);
869808
env->SetMethod(target, "toASCII", ToASCII);
870809
env->SetMethod(target, "getStringWidth", GetStringWidth);
871-
env->SetMethod(target, "getVersion", GetVersion);
872810

873811
// One-shot converters
874812
env->SetMethod(target, "icuErrName", ICUErrorName);

src/node_metadata.cc

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@
1111
#include <openssl/opensslv.h>
1212
#endif // HAVE_OPENSSL
1313

14+
#ifdef NODE_HAVE_I18N_SUPPORT
15+
#include <unicode/timezone.h>
16+
#include <unicode/ulocdata.h>
17+
#include <unicode/uvernum.h>
18+
#include <unicode/uversion.h>
19+
#endif // NODE_HAVE_I18N_SUPPORT
20+
1421
namespace node {
1522

1623
namespace per_process {
@@ -34,6 +41,25 @@ std::string GetOpenSSLVersion() {
3441
}
3542
#endif // HAVE_OPENSSL
3643

44+
#ifdef NODE_HAVE_I18N_SUPPORT
45+
void Metadata::Versions::InitializeIntlVersions() {
46+
UErrorCode status = U_ZERO_ERROR;
47+
48+
const char* tz_version = icu::TimeZone::getTZDataVersion(status);
49+
if (U_SUCCESS(status)) {
50+
tz = tz_version;
51+
}
52+
53+
char buf[U_MAX_VERSION_STRING_LENGTH];
54+
UVersionInfo versionArray;
55+
ulocdata_getCLDRVersion(versionArray, &status);
56+
if (U_SUCCESS(status)) {
57+
u_versionToString(versionArray, buf);
58+
cldr = buf;
59+
}
60+
}
61+
#endif // NODE_HAVE_I18N_SUPPORT
62+
3763
Metadata::Versions::Versions() {
3864
node = NODE_VERSION_STRING;
3965
v8 = v8::V8::GetVersion();
@@ -49,6 +75,11 @@ Metadata::Versions::Versions() {
4975
#if HAVE_OPENSSL
5076
openssl = GetOpenSSLVersion();
5177
#endif
78+
79+
#ifdef NODE_HAVE_I18N_SUPPORT
80+
icu = U_ICU_VERSION;
81+
unicode = U_UNICODE_VERSION;
82+
#endif // NODE_HAVE_I18N_SUPPORT
5283
}
5384

5485
} // namespace node

src/node_metadata.h

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,38 @@ namespace node {
2525
#define NODE_VERSIONS_KEY_CRYPTO(V)
2626
#endif
2727

28+
#ifdef NODE_HAVE_I18N_SUPPORT
29+
#define NODE_VERSIONS_KEY_INTL(V) \
30+
V(cldr) \
31+
V(icu) \
32+
V(tz) \
33+
V(unicode)
34+
#else
35+
#define NODE_VERSIONS_KEY_INTL(V)
36+
#endif // NODE_HAVE_I18N_SUPPORT
37+
2838
#define NODE_VERSIONS_KEYS(V) \
2939
NODE_VERSIONS_KEYS_BASE(V) \
30-
NODE_VERSIONS_KEY_CRYPTO(V)
40+
NODE_VERSIONS_KEY_CRYPTO(V) \
41+
NODE_VERSIONS_KEY_INTL(V)
3142

3243
class Metadata {
3344
public:
45+
Metadata() = default;
46+
Metadata(Metadata&) = delete;
47+
Metadata(Metadata&&) = delete;
48+
Metadata operator=(Metadata&) = delete;
49+
Metadata operator=(Metadata&&) = delete;
50+
3451
struct Versions {
3552
Versions();
53+
54+
#ifdef NODE_HAVE_I18N_SUPPORT
55+
// Must be called on the main thread after
56+
// i18n::InitializeICUDirectory()
57+
void InitializeIntlVersions();
58+
#endif // NODE_HAVE_I18N_SUPPORT
59+
3660
#define V(key) std::string key;
3761
NODE_VERSIONS_KEYS(V)
3862
#undef V

0 commit comments

Comments
 (0)