summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/interpreter/unstarted_runtime.cc20
1 files changed, 11 insertions, 9 deletions
diff --git a/runtime/interpreter/unstarted_runtime.cc b/runtime/interpreter/unstarted_runtime.cc
index d83f5378fd..43e0692eee 100644
--- a/runtime/interpreter/unstarted_runtime.cc
+++ b/runtime/interpreter/unstarted_runtime.cc
@@ -99,7 +99,7 @@ static void CharacterLowerUpper(Thread* self,
JValue* result,
size_t arg_offset,
bool to_lower_case) REQUIRES_SHARED(Locks::mutator_lock_) {
- uint32_t int_value = static_cast<uint32_t>(shadow_frame->GetVReg(arg_offset));
+ int32_t int_value = shadow_frame->GetVReg(arg_offset);
// Only ASCII (7-bit).
if (!isascii(int_value)) {
@@ -109,14 +109,16 @@ static void CharacterLowerUpper(Thread* self,
return;
}
- std::locale c_locale("C");
- char char_value = static_cast<char>(int_value);
-
- if (to_lower_case) {
- result->SetI(std::tolower(char_value, c_locale));
- } else {
- result->SetI(std::toupper(char_value, c_locale));
- }
+ // Constructing a `std::locale("C")` is slow. Use an explicit calculation, compare in debug mode.
+ int32_t masked_value = int_value & ~0x20; // Clear bit distinguishing `A`..`Z` from `a`..`z`.
+ bool is_ascii_letter = ('A' <= masked_value) && (masked_value <= 'Z');
+ int32_t result_value = is_ascii_letter ? (masked_value | (to_lower_case ? 0x20 : 0)) : int_value;
+ DCHECK_EQ(result_value,
+ to_lower_case
+ ? std::tolower(dchecked_integral_cast<char>(int_value), std::locale("C"))
+ : std::toupper(dchecked_integral_cast<char>(int_value), std::locale("C")))
+ << std::boolalpha << to_lower_case;
+ result->SetI(result_value);
}
void UnstartedRuntime::UnstartedCharacterToLowerCase(