Add intrinsics for Memory peek/poke.

Add intrinsics for single memory access (non-array)
peek/poke methods in libcore.io.Memory.

Change-Id: I5d66a5b14ea89875d8afb8252eb293f7d637b83f
diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc
index b366fdd..abc8120 100644
--- a/compiler/dex/quick/gen_invoke.cc
+++ b/compiler/dex/quick/gen_invoke.cc
@@ -1159,6 +1159,39 @@
   return true;
 }
 
+bool Mir2Lir::GenInlinedPeek(CallInfo* info, OpSize size) {
+  RegLocation rl_src_address = info->args[0];  // long address
+  rl_src_address.wide = 0;  // ignore high half in info->args[1]
+  RegLocation rl_dest = InlineTarget(info);
+  RegLocation rl_address = LoadValue(rl_src_address, kCoreReg);
+  RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
+  if (size == kLong) {
+    LoadBaseDispWide(rl_address.low_reg, 0, rl_result.low_reg, rl_result.high_reg, INVALID_SREG);
+    StoreValueWide(rl_dest, rl_result);
+  } else {
+    DCHECK(size == kSignedByte || size == kSignedHalf || size == kWord);
+    LoadBaseDisp(rl_address.low_reg, 0, rl_result.low_reg, size, INVALID_SREG);
+    StoreValue(rl_dest, rl_result);
+  }
+  return true;
+}
+
+bool Mir2Lir::GenInlinedPoke(CallInfo* info, OpSize size) {
+  RegLocation rl_src_address = info->args[0];  // long address
+  rl_src_address.wide = 0;  // ignore high half in info->args[1]
+  RegLocation rl_src_value = info->args[2];  // [size] value
+  RegLocation rl_address = LoadValue(rl_src_address, kCoreReg);
+  if (size == kLong) {
+    RegLocation rl_value = LoadValueWide(rl_src_value, kCoreReg);
+    StoreBaseDispWide(rl_address.low_reg, 0, rl_value.low_reg, rl_value.high_reg);
+  } else {
+    DCHECK(size == kSignedByte || size == kSignedHalf || size == kWord);
+    RegLocation rl_value = LoadValue(rl_src_value, kCoreReg);
+    StoreBaseDisp(rl_address.low_reg, 0, rl_value.low_reg, size);
+  }
+  return true;
+}
+
 bool Mir2Lir::GenInlinedUnsafeGet(CallInfo* info,
                                   bool is_long, bool is_volatile) {
   if (cu_->instruction_set == kMips) {
@@ -1322,6 +1355,32 @@
     if (tgt_method == "java.lang.Thread java.lang.Thread.currentThread()") {
       return GenInlinedCurrentThread(info);
     }
+  } else if (tgt_methods_declaring_class.starts_with("Llibcore/io/Memory;")) {
+    std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
+    if (tgt_method == "byte libcore.io.Memory.peekByte(long)") {
+      return GenInlinedPeek(info, kSignedByte);
+    }
+    if (tgt_method == "int libcore.io.Memory.peekIntNative(long)") {
+      return GenInlinedPeek(info, kWord);
+    }
+    if (tgt_method == "long libcore.io.Memory.peekLongNative(long)") {
+      return GenInlinedPeek(info, kLong);
+    }
+    if (tgt_method == "short libcore.io.Memory.peekShortNative(long)") {
+      return GenInlinedPeek(info, kSignedHalf);
+    }
+    if (tgt_method == "void libcore.io.Memory.pokeByte(long, byte)") {
+      return GenInlinedPoke(info, kSignedByte);
+    }
+    if (tgt_method == "void libcore.io.Memory.pokeIntNative(long, int)") {
+      return GenInlinedPoke(info, kWord);
+    }
+    if (tgt_method == "void libcore.io.Memory.pokeLongNative(long, long)") {
+      return GenInlinedPoke(info, kLong);
+    }
+    if (tgt_method == "void libcore.io.Memory.pokeShortNative(long, short)") {
+      return GenInlinedPoke(info, kSignedHalf);
+    }
   } else if (tgt_methods_declaring_class.starts_with("Lsun/misc/Unsafe;")) {
     std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
     if (tgt_method == "boolean sun.misc.Unsafe.compareAndSwapInt(java.lang.Object, long, int, int)") {
diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h
index 7e9848d..0c2a70c 100644
--- a/compiler/dex/quick/mir_to_lir.h
+++ b/compiler/dex/quick/mir_to_lir.h
@@ -552,6 +552,8 @@
     bool GenInlinedIndexOf(CallInfo* info, bool zero_based);
     bool GenInlinedStringCompareTo(CallInfo* info);
     bool GenInlinedCurrentThread(CallInfo* info);
+    bool GenInlinedPeek(CallInfo* info, OpSize size);
+    bool GenInlinedPoke(CallInfo* info, OpSize size);
     bool GenInlinedUnsafeGet(CallInfo* info, bool is_long, bool is_volatile);
     bool GenInlinedUnsafePut(CallInfo* info, bool is_long, bool is_object,
                              bool is_volatile, bool is_ordered);