Fix ordering of fields with the same name.

While the Java language doesn't allow multiple fields with
the same name in a single class (excluding fields from super
classes), the bytecode specification permits it and tools
such as proguard actually generate them. Define the order of
these fields by their dex file index and relax the check of
field ordering to permit identical names.

Bug: 18211592
Change-Id: I1dee9b2b669a6ea180a2d3a41030efb2aed53950
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 84cbcdc..aaf2da7 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -5216,8 +5216,10 @@
       // Primitive types differ but sizes match. Arbitrarily order by primitive type.
       return type1 < type2;
     }
-    // same basic group? then sort by string.
-    return strcmp(field1->GetName(), field2->GetName()) < 0;
+    // Same basic group? Then sort by dex field index. This is guaranteed to be sorted
+    // by name and for equal names by type id index.
+    // NOTE: This works also for proxies. Their static fields are assigned appropriate indexes.
+    return field1->GetDexFieldIndex() < field2->GetDexFieldIndex();
   }
 };
 
@@ -5342,7 +5344,9 @@
       }
       if (i != 0) {
         mirror::ArtField* prev_field = fields->Get(i - 1u);
-        CHECK_LT(strcmp(prev_field->GetName(), field->GetName()), 0);
+        // NOTE: The field names can be the same. This is not possible in the Java language
+        // but it's valid Java/dex bytecode and for example proguard can generate such bytecode.
+        CHECK_LE(strcmp(prev_field->GetName(), field->GetName()), 0);
       }
       Primitive::Type type = field->GetTypeAsPrimitiveType();
       bool is_primitive = type != Primitive::kPrimNot;
diff --git a/runtime/oat.cc b/runtime/oat.cc
index 2f7357f..bfb27dd 100644
--- a/runtime/oat.cc
+++ b/runtime/oat.cc
@@ -25,7 +25,7 @@
 namespace art {
 
 const uint8_t OatHeader::kOatMagic[] = { 'o', 'a', 't', '\n' };
-const uint8_t OatHeader::kOatVersion[] = { '0', '4', '7', '\0' };
+const uint8_t OatHeader::kOatVersion[] = { '0', '4', '8', '\0' };
 
 static size_t ComputeOatHeaderSize(const SafeMap<std::string, std::string>* variable_data) {
   size_t estimate = 0U;
diff --git a/test/800-smali/expected.txt b/test/800-smali/expected.txt
index f766b0a..1b813bf 100644
--- a/test/800-smali/expected.txt
+++ b/test/800-smali/expected.txt
@@ -2,4 +2,5 @@
 b/17978759
 FloatBadArgReg
 negLong
+sameFieldNames
 Done!
diff --git a/test/800-smali/smali/sameFieldNames.smali b/test/800-smali/smali/sameFieldNames.smali
new file mode 100644
index 0000000..8111fa9
--- /dev/null
+++ b/test/800-smali/smali/sameFieldNames.smali
@@ -0,0 +1,37 @@
+.class public LsameFieldNames;
+.super Ljava/lang/Object;
+
+# Test multiple fields with the same name and different types.
+# (Invalid in Java language but valid in bytecode.)
+.field static public a:D
+.field static public a:S
+.field static public a:J
+.field static public a:F
+.field static public a:Z
+.field static public a:I
+.field static public a:B
+.field static public a:C
+.field static public a:Ljava/lang/Integer;
+.field static public a:Ljava/lang/Long;
+.field static public a:Ljava/lang/Float;
+.field static public a:Ljava/lang/Double;
+.field static public a:Ljava/lang/Boolean;
+.field static public a:Ljava/lang/Void;
+.field static public a:Ljava/lang/Short;
+.field static public a:Ljava/lang/Char;
+.field static public a:Ljava/lang/Byte;
+
+.method public static getInt()I
+    .locals 2
+    const/4 v0, 2
+    sput v0, LsameFieldNames;->a:I
+    sget-object v1, LsameFieldNames;->a:Ljava/lang/Integer;
+    const/4 v1, 0
+    if-nez v1, :fail
+    const/4 v0, 7
+    :ret
+    return v0
+    :fail
+    const/4 v0, 0
+    goto :ret
+.end method
diff --git a/test/800-smali/src/Main.java b/test/800-smali/src/Main.java
index 014edc0..3a0f8ea 100644
--- a/test/800-smali/src/Main.java
+++ b/test/800-smali/src/Main.java
@@ -54,6 +54,7 @@
         testCases.add(new TestCase("FloatBadArgReg", "FloatBadArgReg", "getInt",
             new Object[]{100}, null, 100));
         testCases.add(new TestCase("negLong", "negLong", "negLong", null, null, 122142L));
+        testCases.add(new TestCase("sameFieldNames", "sameFieldNames", "getInt", null, null, 7));
     }
 
     public void runTests() {