ART: Add cutout for Character.toLower/UpperCase
Add support for ASCII codepoint toLowerCase/toUpperCase. Those
inputs are easy, and generally sufficient.
Allows to compile-time initialize:
* android.text.Html$HtmlParser
* java.util.UUID$Holder
* sun.security.ec.ECKeyFactory
Bug: 27265238
(cherry picked from commit 0bdce99fcecdadcbafc8e7a9bb92f491a4f37b2a)
Change-Id: I0f164a7df4f26c0b266cef230e36f6ca3af20bde
diff --git a/runtime/interpreter/unstarted_runtime.cc b/runtime/interpreter/unstarted_runtime.cc
index 9531557..a2a190e 100644
--- a/runtime/interpreter/unstarted_runtime.cc
+++ b/runtime/interpreter/unstarted_runtime.cc
@@ -16,11 +16,13 @@
#include "unstarted_runtime.h"
+#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
#include <cmath>
#include <limits>
+#include <locale>
#include <unordered_map>
#include "ScopedLocalRef.h"
@@ -70,6 +72,43 @@
}
}
+// Restricted support for character upper case / lower case. Only support ASCII, where
+// it's easy. Abort the transaction otherwise.
+static void CharacterLowerUpper(Thread* self,
+ ShadowFrame* shadow_frame,
+ JValue* result,
+ size_t arg_offset,
+ bool to_lower_case) SHARED_REQUIRES(Locks::mutator_lock_) {
+ uint32_t int_value = static_cast<uint32_t>(shadow_frame->GetVReg(arg_offset));
+
+ // Only ASCII (7-bit).
+ if (!isascii(int_value)) {
+ AbortTransactionOrFail(self,
+ "Only support ASCII characters for toLowerCase/toUpperCase: %u",
+ int_value);
+ 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));
+ }
+}
+
+void UnstartedRuntime::UnstartedCharacterToLowerCase(
+ Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset) {
+ CharacterLowerUpper(self, shadow_frame, result, arg_offset, true);
+}
+
+void UnstartedRuntime::UnstartedCharacterToUpperCase(
+ Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset) {
+ CharacterLowerUpper(self, shadow_frame, result, arg_offset, false);
+}
+
// Helper function to deal with class loading in an unstarted runtime.
static void UnstartedRuntimeFindClass(Thread* self, Handle<mirror::String> className,
Handle<mirror::ClassLoader> class_loader, JValue* result,