Skip to content

Commit f69dfc2

Browse files
authored
Merge pull request #36705 from HassanElDesouky/delay-loading-localization
[Localization] Delay loading localization on startup
2 parents 760d799 + 481b29b commit f69dfc2

File tree

4 files changed

+95
-27
lines changed

4 files changed

+95
-27
lines changed

include/swift/AST/DiagnosticEngine.h

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -802,29 +802,11 @@ namespace swift {
802802

803803
bool isPrettyPrintingDecl() const { return IsPrettyPrintingDecl; }
804804

805-
void setLocalization(std::string locale, std::string path) {
805+
void setLocalization(StringRef locale, StringRef path) {
806806
assert(!locale.empty());
807807
assert(!path.empty());
808-
llvm::SmallString<128> filePath(path);
809-
llvm::sys::path::append(filePath, locale);
810-
llvm::sys::path::replace_extension(filePath, ".db");
811-
812-
// If the serialized diagnostics file not available,
813-
// fallback to the `YAML` file.
814-
if (llvm::sys::fs::exists(filePath)) {
815-
if (auto file = llvm::MemoryBuffer::getFile(filePath)) {
816-
localization = std::make_unique<diag::SerializedLocalizationProducer>(
817-
std::move(file.get()), getPrintDiagnosticNames());
818-
}
819-
} else {
820-
llvm::sys::path::replace_extension(filePath, ".yaml");
821-
// In case of missing localization files, we should fallback to messages
822-
// from `.def` files.
823-
if (llvm::sys::fs::exists(filePath)) {
824-
localization = std::make_unique<diag::YAMLLocalizationProducer>(
825-
filePath.str(), getPrintDiagnosticNames());
826-
}
827-
}
808+
localization = diag::LocalizationProducer::producerFor(
809+
locale, path, getPrintDiagnosticNames());
828810
}
829811

830812
void ignoreDiagnostic(DiagID id) {

include/swift/Localization/LocalizationFormat.h

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,12 @@ namespace diag {
4444

4545
using namespace llvm::support;
4646

47+
enum LocalizationProducerState : uint8_t {
48+
NotInitialized,
49+
Initialized,
50+
FailedInitialization
51+
};
52+
4753
class DefToYAMLConverter {
4854
llvm::ArrayRef<const char *> IDs;
4955
llvm::ArrayRef<const char *> Messages;
@@ -162,6 +168,7 @@ class LocalizationProducer {
162168
llvm::BumpPtrAllocator localizationAllocator;
163169
llvm::StringSaver localizationSaver;
164170
bool printDiagnosticNames;
171+
LocalizationProducerState state = NotInitialized;
165172

166173
public:
167174
LocalizationProducer(bool printDiagnosticNames = false)
@@ -173,16 +180,33 @@ class LocalizationProducer {
173180
virtual llvm::StringRef getMessageOr(swift::DiagID id,
174181
llvm::StringRef defaultMessage);
175182

183+
/// \returns a `SerializedLocalizationProducer` pointer if the serialized
184+
/// diagnostics file available, otherwise returns a `YAMLLocalizationProducer`
185+
/// if the `YAML` file is available. If both files aren't available returns a
186+
/// `nullptr`.
187+
static std::unique_ptr<LocalizationProducer>
188+
producerFor(llvm::StringRef locale, llvm::StringRef path,
189+
bool printDiagnosticNames);
190+
176191
virtual ~LocalizationProducer() {}
177192

178193
protected:
194+
LocalizationProducerState getState() const;
195+
196+
/// Used to lazily initialize `LocalizationProducer`s.
197+
/// \returns true if the producer is successfully initialized, false
198+
/// otherwise.
199+
virtual bool initializeImpl() = 0;
200+
virtual void initializeIfNeeded() final;
201+
179202
/// Retrieve a message for the given diagnostic id.
180203
/// \returns empty string if message couldn't be found.
181204
virtual llvm::StringRef getMessage(swift::DiagID id) const = 0;
182205
};
183206

184207
class YAMLLocalizationProducer final : public LocalizationProducer {
185208
std::vector<std::string> diagnostics;
209+
std::string filePath;
186210

187211
public:
188212
/// The diagnostics IDs that are no longer available in `.def`
@@ -194,9 +218,10 @@ class YAMLLocalizationProducer final : public LocalizationProducer {
194218
/// maintained by this producer, callback gets each translation
195219
/// with its unique identifier.
196220
void forEachAvailable(
197-
llvm::function_ref<void(swift::DiagID, llvm::StringRef)> callback) const;
221+
llvm::function_ref<void(swift::DiagID, llvm::StringRef)> callback);
198222

199223
protected:
224+
bool initializeImpl() override;
200225
llvm::StringRef getMessage(swift::DiagID id) const override;
201226
};
202227

@@ -213,6 +238,7 @@ class SerializedLocalizationProducer final : public LocalizationProducer {
213238
bool printDiagnosticNames = false);
214239

215240
protected:
241+
bool initializeImpl() override;
216242
llvm::StringRef getMessage(swift::DiagID id) const override;
217243
};
218244

lib/AST/DiagnosticEngine.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1160,9 +1160,9 @@ DiagnosticEngine::diagnosticStringFor(const DiagID id,
11601160
auto defaultMessage = printDiagnosticNames
11611161
? debugDiagnosticStrings[(unsigned)id]
11621162
: diagnosticStrings[(unsigned)id];
1163-
if (localization) {
1164-
auto localizedMessage =
1165-
localization.get()->getMessageOr(id, defaultMessage);
1163+
1164+
if (auto producer = localization.get()) {
1165+
auto localizedMessage = producer->getMessageOr(id, defaultMessage);
11661166
return localizedMessage;
11671167
}
11681168
return defaultMessage;

lib/Localization/LocalizationFormat.cpp

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,24 @@ bool SerializedLocalizationWriter::emit(llvm::StringRef filePath) {
9393
return OS.has_error();
9494
}
9595

96+
void LocalizationProducer::initializeIfNeeded() {
97+
if (state != NotInitialized)
98+
return;
99+
100+
if (initializeImpl())
101+
state = Initialized;
102+
else
103+
state = FailedInitialization;
104+
}
105+
96106
llvm::StringRef
97107
LocalizationProducer::getMessageOr(swift::DiagID id,
98108
llvm::StringRef defaultMessage) {
109+
initializeIfNeeded();
110+
if (getState() == FailedInitialization) {
111+
return defaultMessage;
112+
}
113+
99114
auto localizedMessage = getMessage(id);
100115
if (localizedMessage.empty())
101116
return defaultMessage;
@@ -108,14 +123,22 @@ LocalizationProducer::getMessageOr(swift::DiagID id,
108123
return localizedMessage;
109124
}
110125

126+
LocalizationProducerState LocalizationProducer::getState() const {
127+
return state;
128+
}
129+
111130
SerializedLocalizationProducer::SerializedLocalizationProducer(
112131
std::unique_ptr<llvm::MemoryBuffer> buffer, bool printDiagnosticNames)
113132
: LocalizationProducer(printDiagnosticNames), Buffer(std::move(buffer)) {
133+
}
134+
135+
bool SerializedLocalizationProducer::initializeImpl() {
114136
auto base =
115137
reinterpret_cast<const unsigned char *>(Buffer.get()->getBufferStart());
116138
auto tableOffset = endian::read<offset_type>(base, little);
117139
SerializedTable.reset(SerializedLocalizationTable::Create(
118140
base + tableOffset, base + sizeof(offset_type), base));
141+
return true;
119142
}
120143

121144
llvm::StringRef
@@ -128,27 +151,64 @@ SerializedLocalizationProducer::getMessage(swift::DiagID id) const {
128151

129152
YAMLLocalizationProducer::YAMLLocalizationProducer(llvm::StringRef filePath,
130153
bool printDiagnosticNames)
131-
: LocalizationProducer(printDiagnosticNames) {
154+
: LocalizationProducer(printDiagnosticNames), filePath(filePath) {
155+
}
156+
157+
bool YAMLLocalizationProducer::initializeImpl() {
132158
auto FileBufOrErr = llvm::MemoryBuffer::getFileOrSTDIN(filePath);
133159
llvm::MemoryBuffer *document = FileBufOrErr->get();
134160
diag::LocalizationInput yin(document->getBuffer());
135161
yin >> diagnostics;
136162
unknownIDs = std::move(yin.unknownIDs);
163+
return true;
137164
}
138165

139166
llvm::StringRef YAMLLocalizationProducer::getMessage(swift::DiagID id) const {
140167
return diagnostics[(unsigned)id];
141168
}
142169

143170
void YAMLLocalizationProducer::forEachAvailable(
144-
llvm::function_ref<void(swift::DiagID, llvm::StringRef)> callback) const {
171+
llvm::function_ref<void(swift::DiagID, llvm::StringRef)> callback) {
172+
initializeIfNeeded();
173+
if (getState() == FailedInitialization) {
174+
return;
175+
}
176+
145177
for (uint32_t i = 0, n = diagnostics.size(); i != n; ++i) {
146178
auto translation = diagnostics[i];
147179
if (!translation.empty())
148180
callback(static_cast<swift::DiagID>(i), translation);
149181
}
150182
}
151183

184+
std::unique_ptr<LocalizationProducer>
185+
LocalizationProducer::producerFor(llvm::StringRef locale, llvm::StringRef path,
186+
bool printDiagnosticNames) {
187+
std::unique_ptr<LocalizationProducer> producer;
188+
llvm::SmallString<128> filePath(path);
189+
llvm::sys::path::append(filePath, locale);
190+
llvm::sys::path::replace_extension(filePath, ".db");
191+
192+
// If the serialized diagnostics file not available,
193+
// fallback to the `YAML` file.
194+
if (llvm::sys::fs::exists(filePath)) {
195+
if (auto file = llvm::MemoryBuffer::getFile(filePath)) {
196+
producer = std::make_unique<diag::SerializedLocalizationProducer>(
197+
std::move(file.get()), printDiagnosticNames);
198+
}
199+
} else {
200+
llvm::sys::path::replace_extension(filePath, ".yaml");
201+
// In case of missing localization files, we should fallback to messages
202+
// from `.def` files.
203+
if (llvm::sys::fs::exists(filePath)) {
204+
producer = std::make_unique<diag::YAMLLocalizationProducer>(
205+
filePath.str(), printDiagnosticNames);
206+
}
207+
}
208+
209+
return producer;
210+
}
211+
152212
llvm::Optional<uint32_t> LocalizationInput::readID(llvm::yaml::IO &io) {
153213
LocalDiagID diagID;
154214
io.mapRequired("id", diagID);

0 commit comments

Comments
 (0)