Merge "Lazily compute object identity hash codes." into dalvik-dev
diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc
index b366fdd..e7bbb04 100644
--- a/compiler/dex/quick/gen_invoke.cc
+++ b/compiler/dex/quick/gen_invoke.cc
@@ -968,8 +968,10 @@
   RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
   if (size == kLong) {
     RegLocation rl_i = LoadValueWide(rl_src_i, kCoreReg);
+    int reg_tmp = AllocTemp();
+    OpRegCopy(reg_tmp, rl_result.low_reg);
     OpRegReg(kOpRev, rl_result.low_reg, rl_i.high_reg);
-    OpRegReg(kOpRev, rl_result.high_reg, rl_i.low_reg);
+    OpRegReg(kOpRev, rl_result.high_reg, reg_tmp);
     StoreValueWide(rl_dest, rl_result);
   } else {
     DCHECK(size == kWord || size == kSignedHalf);
@@ -1159,6 +1161,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 +1357,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);
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 1beb862..98c62ce 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -133,7 +133,7 @@
   UsageError("");
   UsageError("  --compiler-backend=(Quick|QuickGBC|Portable): select compiler backend");
   UsageError("      set.");
-  UsageError("      Example: --instruction-set=Portable");
+  UsageError("      Example: --compiler-backend=Portable");
   UsageError("      Default: Quick");
   UsageError("");
   UsageError("  --host: used with Portable backend to link against host runtime libraries");
diff --git a/runtime/dex_file.cc b/runtime/dex_file.cc
index d3bb483..7e09a48 100644
--- a/runtime/dex_file.cc
+++ b/runtime/dex_file.cc
@@ -457,9 +457,8 @@
   int32_t hi = NumStringIds() - 1;
   while (hi >= lo) {
     int32_t mid = (hi + lo) / 2;
-    uint32_t length;
     const DexFile::StringId& str_id = GetStringId(mid);
-    const char* str = GetStringDataAndUtf16Length(str_id, &length);
+    const char* str = GetStringData(str_id);
     int compare = CompareModifiedUtf8ToModifiedUtf8AsUtf16CodePointValues(string, str);
     if (compare > 0) {
       lo = mid + 1;
@@ -477,9 +476,8 @@
   int32_t hi = NumStringIds() - 1;
   while (hi >= lo) {
     int32_t mid = (hi + lo) / 2;
-    uint32_t length;
     const DexFile::StringId& str_id = GetStringId(mid);
-    const char* str = GetStringDataAndUtf16Length(str_id, &length);
+    const char* str = GetStringData(str_id);
     int compare = CompareModifiedUtf8ToUtf16AsCodePointValues(str, string);
     if (compare > 0) {
       lo = mid + 1;
diff --git a/runtime/dex_file.h b/runtime/dex_file.h
index 7901ea7..a9c24e6 100644
--- a/runtime/dex_file.h
+++ b/runtime/dex_file.h
@@ -575,6 +575,7 @@
     return StringDataByIdx(GetProtoId(method_id.proto_idx_).shorty_idx_);
   }
   const char* GetMethodShorty(const MethodId& method_id, uint32_t* length) const {
+    // Using the UTF16 length is safe here as shorties are guaranteed to be ASCII characters.
     return StringDataAndUtf16LengthByIdx(GetProtoId(method_id.proto_idx_).shorty_idx_, length);
   }
   // Returns the number of class definitions in the .dex file.
diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc
index 71ed95c..aef000c 100644
--- a/runtime/native/dalvik_system_VMRuntime.cc
+++ b/runtime/native/dalvik_system_VMRuntime.cc
@@ -221,8 +221,7 @@
     return;
   }
   const DexFile* dex_file = dex_cache->GetDexFile();
-  uint32_t utf16Size;
-  const char* utf8 = dex_file->StringDataAndUtf16LengthByIdx(string_idx, &utf16Size);
+  const char* utf8 = dex_file->StringDataByIdx(string_idx);
   string = strings[utf8];
   if (string == NULL) {
     return;