creating workflow for mirror::String compression

All-ASCII String characters are stored in 8-bit blocks
instead of 16-bit. The compression has not taken place, but all
workflow are in the code already (changing kUseStringCompression in
string.h file to TRUE will enable the feature)

Notes: Feature works on interpreter only without optimizing

Test art: m ART_TEST_INTERPRETER=true ART_TEST_OPTIMIZING=false
          test-art-host

Also tested with String tests from libcore/:
1. libcore.java.lang.StringTest
2. libcore.java.lang.StringBufferTest
3. libcore.java.lang.StringBuilderTest
4. libcore.java.lang.OldStringTest
5. libcore.java.lang.OldStringBufferTest

Memory improvement is 33% (from 6.03% to 4.03%, total String memory
from all apps per total memory of all apps) measured on Angler
with Hprof tools

Bug: 31040547
Change-Id: I9cc92c265ebf1305fc06b5fc33efd83797660cce
diff --git a/runtime/mirror/string.h b/runtime/mirror/string.h
index d492ba3..8695fe8 100644
--- a/runtime/mirror/string.h
+++ b/runtime/mirror/string.h
@@ -31,6 +31,9 @@
 
 namespace mirror {
 
+// String Compression
+static constexpr bool kUseStringCompression = false;
+
 // C++ mirror of java.lang.String
 class MANAGED String FINAL : public Object {
  public:
@@ -54,18 +57,28 @@
     return &value_[0];
   }
 
+  uint8_t* GetValueCompressed() SHARED_REQUIRES(Locks::mutator_lock_) {
+    return &value_compressed_[0];
+  }
+
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   size_t SizeOf() SHARED_REQUIRES(Locks::mutator_lock_);
 
+  // Taking out the first/uppermost bit because it is not part of actual length value
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   int32_t GetLength() SHARED_REQUIRES(Locks::mutator_lock_) {
+    return GetLengthFromCount(GetCount<kVerifyFlags>());
+  }
+
+  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
+  int32_t GetCount() SHARED_REQUIRES(Locks::mutator_lock_) {
     return GetField32<kVerifyFlags>(OFFSET_OF_OBJECT_MEMBER(String, count_));
   }
 
   void SetCount(int32_t new_count) SHARED_REQUIRES(Locks::mutator_lock_) {
     // Count is invariant so use non-transactional mode. Also disable check as we may run inside
     // a transaction.
-    DCHECK_LE(0, new_count);
+    DCHECK_LE(0, (new_count & INT32_MAX));
     SetField32<false, false>(OFFSET_OF_OBJECT_MEMBER(String, count_), new_count);
   }
 
@@ -82,12 +95,6 @@
 
   String* Intern() SHARED_REQUIRES(Locks::mutator_lock_);
 
-  template <bool kIsInstrumented, typename PreFenceVisitor>
-  ALWAYS_INLINE static String* Alloc(Thread* self, int32_t utf16_length,
-                                     gc::AllocatorType allocator_type,
-                                     const PreFenceVisitor& pre_fence_visitor)
-      SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
-
   template <bool kIsInstrumented>
   ALWAYS_INLINE static String* AllocFromByteArray(Thread* self, int32_t byte_length,
                                                   Handle<ByteArray> array, int32_t offset,
@@ -107,6 +114,11 @@
                                                gc::AllocatorType allocator_type)
       SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
 
+  template <bool kIsInstrumented>
+  ALWAYS_INLINE static String* AllocEmptyString(Thread* self,
+                                                gc::AllocatorType allocator_type)
+      SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
+
   static String* AllocFromStrings(Thread* self, Handle<String> string, Handle<String> string2)
       SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
 
@@ -149,6 +161,10 @@
 
   int32_t FastIndexOf(int32_t ch, int32_t start) SHARED_REQUIRES(Locks::mutator_lock_);
 
+  template <typename MemoryType>
+  int32_t FastIndexOf(MemoryType* chars, int32_t ch, int32_t start)
+      SHARED_REQUIRES(Locks::mutator_lock_);
+
   int32_t CompareTo(String* other) SHARED_REQUIRES(Locks::mutator_lock_);
 
   CharArray* ToCharArray(Thread* self) SHARED_REQUIRES(Locks::mutator_lock_)
@@ -157,6 +173,28 @@
   void GetChars(int32_t start, int32_t end, Handle<CharArray> array, int32_t index)
       SHARED_REQUIRES(Locks::mutator_lock_);
 
+  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
+  bool IsCompressed() SHARED_REQUIRES(Locks::mutator_lock_) {
+    return kUseStringCompression && GetCompressionFlagFromCount(GetCount());
+  }
+
+  bool IsValueNull() SHARED_REQUIRES(Locks::mutator_lock_);
+
+  template<typename MemoryType>
+  static bool AllASCII(const MemoryType* const chars, const int length);
+
+  ALWAYS_INLINE static bool GetCompressionFlagFromCount(const int32_t count) {
+    return kUseStringCompression && ((count & (1u << 31)) != 0);
+  }
+
+  ALWAYS_INLINE static int32_t GetLengthFromCount(const int32_t count) {
+    return kUseStringCompression ? (count & INT32_MAX) : count;
+  }
+
+  ALWAYS_INLINE static int32_t GetFlaggedCount(const int32_t count) {
+    return kUseStringCompression ? (count | (1u << 31)) : count;
+  }
+
   static Class* GetJavaLangString() SHARED_REQUIRES(Locks::mutator_lock_) {
     DCHECK(!java_lang_String_.IsNull());
     return java_lang_String_.Read();
@@ -174,12 +212,24 @@
     SetField32<false, false>(OFFSET_OF_OBJECT_MEMBER(String, hash_code_), new_hash_code);
   }
 
+  template <bool kIsInstrumented, typename PreFenceVisitor>
+  ALWAYS_INLINE static String* Alloc(Thread* self, int32_t utf16_length_with_flag,
+                                     gc::AllocatorType allocator_type,
+                                     const PreFenceVisitor& pre_fence_visitor)
+      SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
+
   // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
+  // First bit (uppermost/leftmost) is taken out for Compressed/Uncompressed flag
+  // [0] Uncompressed: string uses 16-bit memory | [1] Compressed: 8-bit memory
   int32_t count_;
 
   uint32_t hash_code_;
 
-  uint16_t value_[0];
+  // Compression of all-ASCII into 8-bit memory leads to usage one of these fields
+  union {
+    uint16_t value_[0];
+    uint8_t value_compressed_[0];
+  };
 
   static GcRoot<Class> java_lang_String_;