Merge "Reject dex files that attempt to use unspecified class access flags"
diff --git a/dx/Android.mk b/dx/Android.mk
index b31b23b..edf8ca3 100644
--- a/dx/Android.mk
+++ b/dx/Android.mk
@@ -29,6 +29,24 @@
 
 endif # TARGET_BUILD_APPS
 
+# the dexmerger script
+# ============================================================
+include $(CLEAR_VARS)
+LOCAL_IS_HOST_MODULE := true
+LOCAL_MODULE_CLASS := EXECUTABLES
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := dexmerger
+
+include $(BUILD_SYSTEM)/base_rules.mk
+
+$(LOCAL_BUILT_MODULE): $(HOST_OUT_JAVA_LIBRARIES)/dx$(COMMON_JAVA_PACKAGE_SUFFIX)
+$(LOCAL_BUILT_MODULE): $(LOCAL_PATH)/etc/dexmerger | $(ACP)
+	@echo "Copy: $(PRIVATE_MODULE) ($@)"
+	$(copy-file-to-new-target)
+	$(hide) chmod 755 $@
+
+INTERNAL_DALVIK_MODULES += $(LOCAL_INSTALLED_MODULE)
+
 # the jasmin script
 # ============================================================
 include $(CLEAR_VARS)
diff --git a/dx/etc/dexmerger b/dx/etc/dexmerger
new file mode 100644
index 0000000..58fd9ab
--- /dev/null
+++ b/dx/etc/dexmerger
@@ -0,0 +1,89 @@
+#!/bin/bash
+#
+# Copyright (C) 2012 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Set up prog to be the path of this script, including following symlinks,
+# and set up progdir to be the fully-qualified pathname of its directory.
+prog="$0"
+while [ -h "${prog}" ]; do
+    newProg=`/bin/ls -ld "${prog}"`
+    newProg=`expr "${newProg}" : ".* -> \(.*\)$"`
+    if expr "x${newProg}" : 'x/' >/dev/null; then
+        prog="${newProg}"
+    else
+        progdir=`dirname "${prog}"`
+        prog="${progdir}/${newProg}"
+    fi
+done
+oldwd=`pwd`
+progdir=`dirname "${prog}"`
+cd "${progdir}"
+progdir=`pwd`
+prog="${progdir}"/`basename "${prog}"`
+cd "${oldwd}"
+
+jarfile=dx.jar
+libdir="$progdir"
+
+if [ ! -r "$libdir/$jarfile" ]; then
+    # set dx.jar location for the SDK case
+    libdir=`dirname "$progdir"`/platform-tools/lib
+fi
+
+
+if [ ! -r "$libdir/$jarfile" ]; then
+    # set dx.jar location for the Android tree case
+    libdir=`dirname "$progdir"`/framework
+fi
+
+if [ ! -r "$libdir/$jarfile" ]; then
+    echo `basename "$prog"`": can't find $jarfile"
+    exit 1
+fi
+
+# By default, give dexmerger a max heap size of 1 gig. This can be overridden
+# by using a "-J" option (see below).
+defaultMx="-Xmx1024M"
+
+# The following will extract any initial parameters of the form
+# "-J<stuff>" from the command line and pass them to the Java
+# invocation (instead of to dexmerger). This makes it possible for you to add
+# a command-line parameter such as "-JXmx256M" in your scripts, for
+# example. "java" (with no args) and "java -X" give a summary of
+# available options.
+
+javaOpts=""
+
+while expr "x$1" : 'x-J' >/dev/null; do
+    opt=`expr "x$1" : 'x-J\(.*\)'`
+    javaOpts="${javaOpts} -${opt}"
+    if expr "x${opt}" : "xXmx[0-9]" >/dev/null; then
+        defaultMx="no"
+    fi
+    shift
+done
+
+if [ "${defaultMx}" != "no" ]; then
+    javaOpts="${javaOpts} ${defaultMx}"
+fi
+
+if [ "$OSTYPE" = "cygwin" ]; then
+    # For Cygwin, convert the jarfile path into native Windows style.
+    jarpath=`cygpath -w "$libdir/$jarfile"`
+else
+    jarpath="$libdir/$jarfile"
+fi
+
+exec java $javaOpts -cp "$jarpath" com.android.dx.merge.DexMerger "$@"
diff --git a/dx/junit-tests/Android.mk b/dx/junit-tests/Android.mk
index 3f2c611..f999c92 100644
--- a/dx/junit-tests/Android.mk
+++ b/dx/junit-tests/Android.mk
@@ -4,6 +4,6 @@
 include $(CLEAR_VARS)
 LOCAL_SRC_FILES := $(call all-subdir-java-files)
 LOCAL_JAVA_LIBRARIES := dx junit
-LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_TAGS := tests
 LOCAL_MODULE:= dx-tests
 include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/dx/junit-tests/com/android/dx/util/BitIntSetTest.java b/dx/junit-tests/com/android/dx/util/BitIntSetTest.java
index 6d1b9e8..d46d14f 100644
--- a/dx/junit-tests/com/android/dx/util/BitIntSetTest.java
+++ b/dx/junit-tests/com/android/dx/util/BitIntSetTest.java
@@ -14,11 +14,8 @@
  * limitations under the License.
  */
 
-package com.android.dx.util._tests;
+package com.android.dx.util;
 
-import com.android.dx.util.BitIntSet;
-import com.android.dx.util.IntIterator;
-import com.android.dx.util.ListIntSet;
 import java.util.NoSuchElementException;
 import junit.framework.TestCase;
 
diff --git a/dx/junit-tests/com/android/dx/util/BitsTest.java b/dx/junit-tests/com/android/dx/util/BitsTest.java
index 5cf2b6f..e427513 100644
--- a/dx/junit-tests/com/android/dx/util/BitsTest.java
+++ b/dx/junit-tests/com/android/dx/util/BitsTest.java
@@ -14,9 +14,8 @@
  * limitations under the License.
  */
 
-package com.android.dx.util._tests;
+package com.android.dx.util;
 
-import com.android.dx.util.Bits;
 import junit.framework.TestCase;
 
 public final class BitsTest extends TestCase {
diff --git a/dx/junit-tests/com/android/dx/util/IntListTest.java b/dx/junit-tests/com/android/dx/util/IntListTest.java
index 8b72da1..7a53a67 100644
--- a/dx/junit-tests/com/android/dx/util/IntListTest.java
+++ b/dx/junit-tests/com/android/dx/util/IntListTest.java
@@ -14,9 +14,8 @@
  * limitations under the License.
  */
 
-package com.android.dx.util._tests;
+package com.android.dx.util;
 
-import com.android.dx.util.IntList;
 import junit.framework.TestCase;
 
 public final class IntListTest extends TestCase {
diff --git a/dx/junit-tests/com/android/dx/util/ListIntSetTest.java b/dx/junit-tests/com/android/dx/util/ListIntSetTest.java
index dd72b6b..868e630 100644
--- a/dx/junit-tests/com/android/dx/util/ListIntSetTest.java
+++ b/dx/junit-tests/com/android/dx/util/ListIntSetTest.java
@@ -14,11 +14,8 @@
  * limitations under the License.
  */
 
-package com.android.dx.util._tests;
+package com.android.dx.util;
 
-import com.android.dx.util.BitIntSet;
-import com.android.dx.util.IntIterator;
-import com.android.dx.util.ListIntSet;
 import java.util.NoSuchElementException;
 import junit.framework.TestCase;
 
diff --git a/dx/src/com/android/dx/dex/code/form/Form12x.java b/dx/src/com/android/dx/dex/code/form/Form12x.java
index b4d5b4a..a2e88e3 100644
--- a/dx/src/com/android/dx/dex/code/form/Form12x.java
+++ b/dx/src/com/android/dx/dex/code/form/Form12x.java
@@ -112,9 +112,33 @@
     public BitSet compatibleRegs(DalvInsn insn) {
         RegisterSpecList regs = insn.getRegisters();
         BitSet bits = new BitSet(2);
+        int r0 = regs.get(0).getReg();
+        int r1 = regs.get(1).getReg();
 
-        bits.set(0, unsignedFitsInNibble(regs.get(0).getReg()));
-        bits.set(1, unsignedFitsInNibble(regs.get(1).getReg()));
+        switch (regs.size()) {
+          case 2: {
+            bits.set(0, unsignedFitsInNibble(r0));
+            bits.set(1, unsignedFitsInNibble(r1));
+            break;
+          }
+          case 3: {
+            if (r0 != r1) {
+                bits.set(0, false);
+                bits.set(1, false);
+            } else {
+                boolean dstRegComp = unsignedFitsInNibble(r1);
+                bits.set(0, dstRegComp);
+                bits.set(1, dstRegComp);
+            }
+
+            bits.set(2, unsignedFitsInNibble(regs.get(2).getReg()));
+            break;
+          }
+          default: {
+            throw new AssertionError();
+          }
+        }
+
         return bits;
     }
 
diff --git a/dx/src/com/android/dx/merge/DexMerger.java b/dx/src/com/android/dx/merge/DexMerger.java
index 0a92e48..8080947 100644
--- a/dx/src/com/android/dx/merge/DexMerger.java
+++ b/dx/src/com/android/dx/merge/DexMerger.java
@@ -805,7 +805,7 @@
             if (method.getCodeOffset() == 0) {
                 classDataOut.writeUleb128(0);
             } else {
-                codeOut.alignToFourBytes();
+                codeOut.alignToFourBytesWithZeroFill();
                 classDataOut.writeUleb128(codeOut.getPosition());
                 transformCode(in, in.readCode(method), indexMap);
             }
@@ -1038,6 +1038,7 @@
             annotationsSet = dexMerger.annotationSetOut.used();
             annotationsSetRefList = dexMerger.annotationSetRefListOut.used();
             annotation = dexMerger.annotationOut.used();
+            fourByteAlign();
         }
 
         private void plus(TableOfContents contents, boolean exact) {
@@ -1102,20 +1103,23 @@
     }
 
     public static void main(String[] args) throws IOException {
-        if (args.length != 3) {
+        if (args.length < 2) {
             printUsage();
             return;
         }
 
-        Dex dexA = new Dex(new File(args[1]));
-        Dex dexB = new Dex(new File(args[2]));
-        Dex merged = new DexMerger(dexA, dexB, CollisionPolicy.KEEP_FIRST).merge();
+        Dex merged = new Dex(new File(args[1]));
+        for (int i = 2; i < args.length; i++) {
+            Dex toMerge = new Dex(new File(args[i]));
+            merged = new DexMerger(merged, toMerge, CollisionPolicy.KEEP_FIRST).merge();
+        }
         merged.writeTo(new File(args[0]));
     }
 
     private static void printUsage() {
-        System.out.println("Usage: DexMerger <out.dex> <a.dex> <b.dex>");
+        System.out.println("Usage: DexMerger <out.dex> <a.dex> <b.dex> ...");
         System.out.println();
-        System.out.println("If both a and b define the same classes, a's copy will be used.");
+        System.out.println(
+            "If a class is defined in several dex, the class found in the first dex will be used.");
     }
 }
diff --git a/libdex/DexSwapVerify.cpp b/libdex/DexSwapVerify.cpp
index 24a86f9..4b3cf44 100644
--- a/libdex/DexSwapVerify.cpp
+++ b/libdex/DexSwapVerify.cpp
@@ -187,7 +187,7 @@
  */
 #define CHECK_INDEX(_field, _limit) {                                       \
         if ((_field) >= (_limit)) {                                         \
-            ALOGW("Bad index: %s(%u) > %s(%u)",                              \
+            ALOGW("Bad index: %s(%u) > %s(%u)",                             \
                 #_field, (u4)(_field), #_limit, (u4)(_limit));              \
             return 0;                                                       \
         }                                                                   \
@@ -206,7 +206,7 @@
  */
 #define CHECK_INDEX_OR_NOINDEX(_field, _limit) {                            \
         if ((_field) != kDexNoIndex && (_field) >= (_limit)) {              \
-            ALOGW("Bad index: %s(%u) > %s(%u)",                              \
+            ALOGW("Bad index: %s(%u) > %s(%u)",                             \
                 #_field, (u4)(_field), #_limit, (u4)(_limit));              \
             return 0;                                                       \
         }                                                                   \
diff --git a/vm/native/dalvik_system_VMRuntime.cpp b/vm/native/dalvik_system_VMRuntime.cpp
index 72bad29..f44f7d8 100644
--- a/vm/native/dalvik_system_VMRuntime.cpp
+++ b/vm/native/dalvik_system_VMRuntime.cpp
@@ -21,7 +21,6 @@
 #include "ScopedPthreadMutexLock.h"
 #include "native/InternalNativePriv.h"
 
-#include <cutils/array.h>
 #include <limits.h>