Skip to content

Commit de6f1f5

Browse files
joyeecheungaddaleax
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: #25115 Reviewed-By: Steven R Loomis <srloomis@us.ibm.com> Reviewed-By: Richard Lau <riclau@uk.ibm.com> Reviewed-By: Minwoo Jung <minwoo@nodesource.com> Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent e5b4af4 commit de6f1f5

File tree

5 files changed

+61
-85
lines changed

5 files changed

+61
-85
lines changed

lib/internal/bootstrap/node.js

-21
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,6 @@ function startup() {
3939
// Do this good and early, since it handles errors.
4040
setupProcessFatal();
4141

42-
setupProcessICUVersions();
43-
4442
setupGlobalVariables();
4543

4644
// Bootstrappers for all threads, including worker threads and main thread
@@ -647,25 +645,6 @@ function setupProcessFatal() {
647645
};
648646
}
649647

650-
function setupProcessICUVersions() {
651-
const icu = internalBinding('config').hasIntl ?
652-
internalBinding('icu') : undefined;
653-
if (!icu) return; // no Intl/ICU: nothing to add here.
654-
// With no argument, getVersion() returns a comma separated list
655-
// of possible types.
656-
const versionTypes = icu.getVersion().split(',');
657-
658-
for (var n = 0; n < versionTypes.length; n++) {
659-
const name = versionTypes[n];
660-
const version = icu.getVersion(name);
661-
Object.defineProperty(process.versions, name, {
662-
writable: false,
663-
enumerable: true,
664-
value: version
665-
});
666-
}
667-
}
668-
669648
function wrapForBreakOnFirstLine(source) {
670649
if (!process._breakFirstLine)
671650
return source;

src/node.cc

+5-1
Original file line numberDiff line numberDiff line change
@@ -880,7 +880,10 @@ void SetupProcessObject(Environment* env,
880880
READONLY_PROPERTY(process, "versions", versions);
881881

882882
#define V(key) \
883-
READONLY_STRING_PROPERTY(versions, #key, per_process::metadata.versions.key);
883+
if (!per_process::metadata.versions.key.empty()) { \
884+
READONLY_STRING_PROPERTY( \
885+
versions, #key, per_process::metadata.versions.key); \
886+
}
884887
NODE_VERSIONS_KEYS(V)
885888
#undef V
886889

@@ -1672,6 +1675,7 @@ void Init(std::vector<std::string>* argv,
16721675
argv->at(0).c_str());
16731676
exit(9);
16741677
}
1678+
per_process::metadata.versions.InitializeIntlVersions();
16751679
#endif
16761680

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

src/node_i18n.cc

-62
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

+31
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,13 @@
1212
#include <openssl/opensslv.h>
1313
#endif // HAVE_OPENSSL
1414

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

1724
namespace per_process {
@@ -35,6 +42,25 @@ std::string GetOpenSSLVersion() {
3542
}
3643
#endif // HAVE_OPENSSL
3744

45+
#ifdef NODE_HAVE_I18N_SUPPORT
46+
void Metadata::Versions::InitializeIntlVersions() {
47+
UErrorCode status = U_ZERO_ERROR;
48+
49+
const char* tz_version = icu::TimeZone::getTZDataVersion(status);
50+
if (U_SUCCESS(status)) {
51+
tz = tz_version;
52+
}
53+
54+
char buf[U_MAX_VERSION_STRING_LENGTH];
55+
UVersionInfo versionArray;
56+
ulocdata_getCLDRVersion(versionArray, &status);
57+
if (U_SUCCESS(status)) {
58+
u_versionToString(versionArray, buf);
59+
cldr = buf;
60+
}
61+
}
62+
#endif // NODE_HAVE_I18N_SUPPORT
63+
3864
Metadata::Versions::Versions() {
3965
node = NODE_VERSION_STRING;
4066
v8 = v8::V8::GetVersion();
@@ -57,6 +83,11 @@ Metadata::Versions::Versions() {
5783
#if HAVE_OPENSSL
5884
openssl = GetOpenSSLVersion();
5985
#endif
86+
87+
#ifdef NODE_HAVE_I18N_SUPPORT
88+
icu = U_ICU_VERSION;
89+
unicode = U_UNICODE_VERSION;
90+
#endif // NODE_HAVE_I18N_SUPPORT
6091
}
6192

6293
} // namespace node

src/node_metadata.h

+25-1
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,38 @@ namespace node {
2626
#define NODE_VERSIONS_KEY_CRYPTO(V)
2727
#endif
2828

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

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

0 commit comments

Comments
 (0)