Refactor and optimize memory region bit functions

Move optimized bit reading from FieldEncoding to MemoryRegion,
added optimized StoreBits to MemoryRegion.

Compilation of a large app on host:
Before:
Time -j1: 31.897s
2.00% art::MemoryRegion::StoreBits(unsigned long, unsigned int, unsigned long)

After:
Time -j1: 29.620s
0.39% art::MemoryRegion::StoreBits(unsigned long, unsigned int, unsigned long)

Bug: 34621054

Test: test-art-host

Change-Id: I0509613da83cc5741d5cfada3f8a8af503784e9e
diff --git a/runtime/memory_region.cc b/runtime/memory_region.cc
index a5c70c3..5bf0f40 100644
--- a/runtime/memory_region.cc
+++ b/runtime/memory_region.cc
@@ -33,4 +33,36 @@
           from.pointer(), from.size());
 }
 
+void MemoryRegion::StoreBits(uintptr_t bit_offset, uint32_t value, size_t length) {
+  DCHECK_LE(value, MaxInt<uint32_t>(length));
+  DCHECK_LE(length, BitSizeOf<uint32_t>());
+  DCHECK_LE(bit_offset + length, size_in_bits());
+  if (length == 0) {
+    return;
+  }
+  // Bits are stored in this order {7 6 5 4 3 2 1 0}.
+  // How many remaining bits in current byte is (bit_offset % kBitsPerByte) + 1.
+  uint8_t* out = ComputeInternalPointer<uint8_t>(bit_offset >> kBitsPerByteLog2);
+  auto orig_len = length;
+  auto orig_value = value;
+  uintptr_t bit_remainder = bit_offset % kBitsPerByte;
+  while (true) {
+    const uintptr_t remaining_bits = kBitsPerByte - bit_remainder;
+    if (length <= remaining_bits) {
+      // Length is smaller than all of remainder bits.
+      size_t mask = ((1 << length) - 1) << bit_remainder;
+      *out = (*out & ~mask) | (value << bit_remainder);
+      break;
+    }
+    // Copy remaining bits in current byte.
+    size_t value_mask = (1 << remaining_bits) - 1;
+    *out = (*out & ~(value_mask << bit_remainder)) | ((value & value_mask) << bit_remainder);
+    value >>= remaining_bits;
+    bit_remainder = 0;
+    length -= remaining_bits;
+    ++out;
+  }
+  DCHECK_EQ(LoadBits(bit_offset, orig_len), orig_value) << bit_offset << " " << orig_len;
+}
+
 }  // namespace art