String compression on intrinsics x86 and x86_64

Changes on intrinsics and Code Generation (x86 and x86_64)
for string compression feature. Currently the feature is off.

The size of boot.oat and boot.art for x86 before and after the
changes (feature OFF) are still. When the feature ON,
boot.oat increased by 0.83% and boot.art decreased by 19.32%.

Meanwhile for x86_64, size of boot.oat and boot.art before and
after changes (feature OFF) are still. When the feature ON,
boot.oat increased by 0.87% and boot.art decreased by 6.59%.

Turn feature on: runtime/mirror/string.h (kUseStringCompression = true)
runtime/asm_support.h (STRING_COMPRESSION_FEATURE 1)

Test: m -j31 test-art-host
All tests passed both when the mirror::kUseStringCompression
is ON and OFF.

The jni_internal_test changed to assert an empty string length
to be equal -(1 << 31) as it is compressed.

Bug: 31040547
Change-Id: Ia447c9b147cabb6a69e6ded86be1fe0c46d9638d
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index f9a3e42..b243ee0 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -198,6 +198,9 @@
         length_loc = Location::RegisterLocation(calling_convention.GetRegisterAt(2));
       }
       __ movl(length_loc.AsRegister<CpuRegister>(), array_len);
+      if (mirror::kUseStringCompression) {
+        __ andl(length_loc.AsRegister<CpuRegister>(), Immediate(INT32_MAX));
+      }
     }
 
     // We're moving two locations to locations that could overlap, so we need a parallel
@@ -4485,7 +4488,21 @@
 
     case Primitive::kPrimChar: {
       CpuRegister out = out_loc.AsRegister<CpuRegister>();
-      __ movzxw(out, CodeGeneratorX86_64::ArrayAddress(obj, index, TIMES_2, data_offset));
+      if (mirror::kUseStringCompression && instruction->IsStringCharAt()) {
+        // Branch cases into compressed and uncompressed for each index's type.
+        uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
+        NearLabel done, not_compressed;
+        __ cmpl(Address(obj, count_offset), Immediate(0));
+        codegen_->MaybeRecordImplicitNullCheck(instruction);
+        __ j(kGreaterEqual, &not_compressed);
+        __ movzxb(out, CodeGeneratorX86_64::ArrayAddress(obj, index, TIMES_1, data_offset));
+        __ jmp(&done);
+        __ Bind(&not_compressed);
+        __ movzxw(out, CodeGeneratorX86_64::ArrayAddress(obj, index, TIMES_2, data_offset));
+        __ Bind(&done);
+      } else {
+        __ movzxw(out, CodeGeneratorX86_64::ArrayAddress(obj, index, TIMES_2, data_offset));
+      }
       break;
     }
 
@@ -4807,6 +4824,10 @@
   CpuRegister out = locations->Out().AsRegister<CpuRegister>();
   __ movl(out, Address(obj, offset));
   codegen_->MaybeRecordImplicitNullCheck(instruction);
+  // Mask out most significant bit in case the array is String's array of char.
+  if (mirror::kUseStringCompression && instruction->IsStringLength()) {
+    __ andl(out, Immediate(INT32_MAX));
+  }
 }
 
 void LocationsBuilderX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
@@ -4856,13 +4877,23 @@
       uint32_t len_offset = CodeGenerator::GetArrayLengthOffset(array_length->AsArrayLength());
       Location array_loc = array_length->GetLocations()->InAt(0);
       Address array_len(array_loc.AsRegister<CpuRegister>(), len_offset);
-      if (index_loc.IsConstant()) {
-        int32_t value = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
-        __ cmpl(array_len, Immediate(value));
+      if (mirror::kUseStringCompression && instruction->IsStringCharAt()) {
+        CpuRegister length_reg = CpuRegister(TMP);
+        __ movl(length_reg, array_len);
+        codegen_->MaybeRecordImplicitNullCheck(array_length);
+        __ andl(length_reg, Immediate(INT32_MAX));
+        codegen_->GenerateIntCompare(length_reg, index_loc);
       } else {
-        __ cmpl(array_len, index_loc.AsRegister<CpuRegister>());
+        // Checking the bound for general case:
+        // Array of char or String's array when the compression feature off.
+        if (index_loc.IsConstant()) {
+          int32_t value = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
+          __ cmpl(array_len, Immediate(value));
+        } else {
+          __ cmpl(array_len, index_loc.AsRegister<CpuRegister>());
+        }
+        codegen_->MaybeRecordImplicitNullCheck(array_length);
       }
-      codegen_->MaybeRecordImplicitNullCheck(array_length);
     } else {
       codegen_->GenerateIntCompare(length_loc, index_loc);
     }
@@ -6525,13 +6556,17 @@
 
 void CodeGeneratorX86_64::GenerateIntCompare(Location lhs, Location rhs) {
   CpuRegister lhs_reg = lhs.AsRegister<CpuRegister>();
+  GenerateIntCompare(lhs_reg, rhs);
+}
+
+void CodeGeneratorX86_64::GenerateIntCompare(CpuRegister lhs, Location rhs) {
   if (rhs.IsConstant()) {
     int32_t value = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
-    Compare32BitValue(lhs_reg, value);
+    Compare32BitValue(lhs, value);
   } else if (rhs.IsStackSlot()) {
-    __ cmpl(lhs_reg, Address(CpuRegister(RSP), rhs.GetStackIndex()));
+    __ cmpl(lhs, Address(CpuRegister(RSP), rhs.GetStackIndex()));
   } else {
-    __ cmpl(lhs_reg, rhs.AsRegister<CpuRegister>());
+    __ cmpl(lhs, rhs.AsRegister<CpuRegister>());
   }
 }