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/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h
index 90c8227..acdc270 100644
--- a/runtime/interpreter/interpreter_common.h
+++ b/runtime/interpreter/interpreter_common.h
@@ -450,7 +450,7 @@
       oss << StringPrintf(" vreg%u=0x%08X", i, raw_value);
       if (ref_value != nullptr) {
         if (ref_value->GetClass()->IsStringClass() &&
-            ref_value->AsString()->GetValue() != nullptr) {
+            !ref_value->AsString()->IsValueNull()) {
           oss << "/java.lang.String \"" << ref_value->AsString()->ToModifiedUtf8() << "\"";
         } else {
           oss << "/" << PrettyTypeOf(ref_value);
diff --git a/runtime/interpreter/interpreter_goto_table_impl.cc b/runtime/interpreter/interpreter_goto_table_impl.cc
index 43b2778..6aba898 100644
--- a/runtime/interpreter/interpreter_goto_table_impl.cc
+++ b/runtime/interpreter/interpreter_goto_table_impl.cc
@@ -530,8 +530,7 @@
     if (LIKELY(c != nullptr)) {
       if (UNLIKELY(c->IsStringClass())) {
         gc::AllocatorType allocator_type = Runtime::Current()->GetHeap()->GetCurrentAllocator();
-        mirror::SetStringCountVisitor visitor(0);
-        obj = String::Alloc<true>(self, 0, allocator_type, visitor);
+        obj = mirror::String::AllocEmptyString<true>(self, allocator_type);
       } else {
         obj = AllocObjectFromCode<do_access_check, true>(
             inst->VRegB_21c(), shadow_frame.GetMethod(), self,
diff --git a/runtime/interpreter/interpreter_switch_impl.cc b/runtime/interpreter/interpreter_switch_impl.cc
index a6349fc..582fc9b 100644
--- a/runtime/interpreter/interpreter_switch_impl.cc
+++ b/runtime/interpreter/interpreter_switch_impl.cc
@@ -477,8 +477,7 @@
         if (LIKELY(c != nullptr)) {
           if (UNLIKELY(c->IsStringClass())) {
             gc::AllocatorType allocator_type = Runtime::Current()->GetHeap()->GetCurrentAllocator();
-            mirror::SetStringCountVisitor visitor(0);
-            obj = String::Alloc<true>(self, 0, allocator_type, visitor);
+            obj = mirror::String::AllocEmptyString<true>(self, allocator_type);
           } else {
             obj = AllocObjectFromCode<do_access_check, true>(
               inst->VRegB_21c(), shadow_frame.GetMethod(), self,
diff --git a/runtime/interpreter/mterp/mterp.cc b/runtime/interpreter/mterp/mterp.cc
index c25cd78..20a0753 100644
--- a/runtime/interpreter/mterp/mterp.cc
+++ b/runtime/interpreter/mterp/mterp.cc
@@ -358,8 +358,7 @@
   if (LIKELY(c != nullptr)) {
     if (UNLIKELY(c->IsStringClass())) {
       gc::AllocatorType allocator_type = Runtime::Current()->GetHeap()->GetCurrentAllocator();
-      mirror::SetStringCountVisitor visitor(0);
-      obj = String::Alloc<true>(self, 0, allocator_type, visitor);
+      obj = mirror::String::AllocEmptyString<true>(self, allocator_type);
     } else {
       obj = AllocObjectFromCode<false, true>(
         inst->VRegB_21c(), shadow_frame->GetMethod(), self,
diff --git a/runtime/interpreter/unstarted_runtime_test.cc b/runtime/interpreter/unstarted_runtime_test.cc
index 7e1f795..c324600 100644
--- a/runtime/interpreter/unstarted_runtime_test.cc
+++ b/runtime/interpreter/unstarted_runtime_test.cc
@@ -401,8 +401,23 @@
   interpreter::DoCall<false, false>(method, self, *shadow_frame, inst, inst_data[0], &result);
   mirror::String* string_result = reinterpret_cast<mirror::String*>(result.GetL());
   EXPECT_EQ(string_arg->GetLength(), string_result->GetLength());
-  EXPECT_EQ(memcmp(string_arg->GetValue(), string_result->GetValue(),
-                   string_arg->GetLength() * sizeof(uint16_t)), 0);
+
+  if (string_arg->IsCompressed() && string_result->IsCompressed()) {
+    EXPECT_EQ(memcmp(string_arg->GetValueCompressed(), string_result->GetValueCompressed(),
+                     string_arg->GetLength() * sizeof(uint8_t)), 0);
+  } else if (!string_arg->IsCompressed() && !string_result->IsCompressed()) {
+    EXPECT_EQ(memcmp(string_arg->GetValue(), string_result->GetValue(),
+                     string_arg->GetLength() * sizeof(uint16_t)), 0);
+  } else {
+    bool equal = true;
+    for (int i = 0; i < string_arg->GetLength(); ++i) {
+      if (string_arg->CharAt(i) != string_result->CharAt(i)) {
+        equal = false;
+        break;
+      }
+    }
+    EXPECT_EQ(equal, true);
+  }
 
   ShadowFrame::DeleteDeoptimizedFrame(shadow_frame);
 }