am 64b928e: AI 148694: Manually copied from cupcake_dcm CL 148669-p9.  W

Merge commit '64b928e82a3b91b339ff9ee980c4a0c020daa251' into donut

* commit '64b928e82a3b91b339ff9ee980c4a0c020daa251':
  AI 148694: Manually copied from cupcake_dcm CL 148669-p9.  When resetting the
diff --git a/dexdump/DexDump.c b/dexdump/DexDump.c
index a4d97eb..c5714ea 100644
--- a/dexdump/DexDump.c
+++ b/dexdump/DexDump.c
@@ -13,11 +13,21 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 /*
  * The "dexdump" tool is intended to mimic "objdump".  When possible, use
  * similar command-line arguments.
  *
- * TODO: rework the output format to be more regexp-friendly
+ * TODO: rework the "plain" output format to be more regexp-friendly
+ *
+ * Differences between XML output and the "current.xml" file:
+ * - classes in same package are not all grouped together; generally speaking
+ *   nothing is sorted
+ * - no "deprecated" on fields and methods
+ * - no "value" on fields
+ * - no parameter names
+ * - no generic signatures on parameters, e.g. type="java.lang.Class<?>"
+ * - class shows declared fields and methods; does not show inherited fields
  */
 #include "libdex/DexFile.h"
 #include "libdex/DexCatch.h"
@@ -43,12 +53,21 @@
 static InstructionWidth* gInstrWidth;
 static InstructionFormat* gInstrFormat;
 
+typedef enum OutputFormat {
+    OUTPUT_PLAIN = 0,               /* default */
+    OUTPUT_XML,                     /* fancy */
+} OutputFormat;
+
 /* command-line options */
 struct {
     bool disassemble;
     bool showFileHeaders;
     bool showSectionHeaders;
+    bool ignoreBadChecksum;
+    OutputFormat outputFormat;
     const char* tempFileName;
+    bool exportsOnly;
+    bool verbose;
 } gOptions;
 
 /* basic info about a field or method */
@@ -67,34 +86,134 @@
 }   
 
 /*
- * Return a newly-allocated string for the "dot version" of the class
- * name for the given type descriptor. That is, The initial "L" and
- * final ";" (if any) have been removed and all occurrences of '/'
- * have been changed to '.'.
+ * Converts a single-character primitive type into its human-readable
+ * equivalent.
+ */
+static const char* primitiveTypeLabel(char typeChar)
+{
+    switch (typeChar) {
+    case 'B':   return "byte";
+    case 'C':   return "char";
+    case 'D':   return "double";
+    case 'F':   return "float";
+    case 'I':   return "int";
+    case 'J':   return "long";
+    case 'S':   return "short";
+    case 'V':   return "void";
+    case 'Z':   return "boolean";
+    default:
+                return "UNKNOWN";
+    }
+}
+
+/*
+ * Converts a type descriptor to human-readable "dotted" form.  For
+ * example, "Ljava/lang/String;" becomes "java.lang.String", and
+ * "[I" becomes "int[]".  Also converts '$' to '.', which means this
+ * form can't be converted back to a descriptor.
  */
 static char* descriptorToDot(const char* str)
 {
-    size_t at = strlen(str);
+    int targetLen = strlen(str);
+    int offset = 0;
+    int arrayDepth = 0;
     char* newStr;
 
-    if (str[0] == 'L') {
-        assert(str[at - 1] == ';');
-        at -= 2; /* Two fewer chars to copy. */
-        str++; /* Skip the 'L'. */
+    /* strip leading [s; will be added to end */
+    while (targetLen > 1 && str[offset] == '[') {
+        offset++;
+        targetLen--;
+    }
+    arrayDepth = offset;
+
+    if (targetLen == 1) {
+        /* primitive type */
+        str = primitiveTypeLabel(str[offset]);
+        offset = 0;
+        targetLen = strlen(str);
+    } else {
+        /* account for leading 'L' and trailing ';' */
+        if (targetLen >= 2 && str[offset] == 'L' &&
+            str[offset+targetLen-1] == ';')
+        {
+            targetLen -= 2;
+            offset++;
+        }
     }
 
-    newStr = malloc(at + 1); /* Add one for the '\0'. */
-    newStr[at] = '\0';
+    newStr = malloc(targetLen + arrayDepth * 2 +1);
 
-    while (at > 0) {
-        at--;
-        newStr[at] = (str[at] == '/') ? '.' : str[at];
+    /* copy class name over */
+    int i;
+    for (i = 0; i < targetLen; i++) {
+        char ch = str[offset + i];
+        newStr[i] = (ch == '/' || ch == '$') ? '.' : ch;
+    }
+
+    /* add the appropriate number of brackets for arrays */
+    while (arrayDepth-- > 0) {
+        newStr[i++] = '[';
+        newStr[i++] = ']';
+    }
+    newStr[i] = '\0';
+    assert(i == targetLen + arrayDepth * 2);
+
+    return newStr;
+}
+
+/*
+ * Converts the class name portion of a type descriptor to human-readable
+ * "dotted" form.
+ *
+ * Returns a newly-allocated string.
+ */
+static char* descriptorClassToDot(const char* str)
+{
+    const char* lastSlash;
+    char* newStr;
+    char* cp;
+
+    /* reduce to just the class name, trimming trailing ';' */
+    lastSlash = strrchr(str, '/');
+    if (lastSlash == NULL)
+        lastSlash = str + 1;        /* start past 'L' */
+    else
+        lastSlash++;                /* start past '/' */
+
+    newStr = strdup(lastSlash);
+    newStr[strlen(lastSlash)-1] = '\0';
+    for (cp = newStr; *cp != '\0'; cp++) {
+        if (*cp == '$')
+            *cp = '.';
     }
 
     return newStr;
 }
 
 /*
+ * Returns a quoted string representing the boolean value.
+ */
+static const char* quotedBool(bool val)
+{
+    if (val)
+        return "\"true\"";
+    else
+        return "\"false\"";
+}
+
+static const char* quotedVisibility(u4 accessFlags)
+{
+    if ((accessFlags & ACC_PUBLIC) != 0)
+        return "\"public\"";
+    else if ((accessFlags & ACC_PROTECTED) != 0)
+        return "\"protected\"";
+    else if ((accessFlags & ACC_PRIVATE) != 0)
+        return "\"private\"";
+    else
+        return "\"package\"";
+}
+
+/*
  * Count the number of '1' bits in a word.
  *
  * Having completed this, I'm ready for an interview at Google.
@@ -114,7 +233,6 @@
     return count;
 }
 
-
 /*
  * Flag for use with createAccessFlagStr().
  */
@@ -310,7 +428,7 @@
 }
 
 /*
- * Dump an interface.
+ * Dump an interface that a class declares to implement.
  */
 void dumpInterface(const DexFile* pDexFile, const DexTypeItem* pTypeItem,
     int i)
@@ -318,7 +436,13 @@
     const char* interfaceName =
         dexStringByTypeIdx(pDexFile, pTypeItem->typeIdx);
 
-    printf("    #%d              : '%s'\n", i, interfaceName);
+    if (gOptions.outputFormat == OUTPUT_PLAIN) {
+        printf("    #%d              : '%s'\n", i, interfaceName);
+    } else {
+        char* dotted = descriptorToDot(interfaceName);
+        printf("<implements name=\"%s\">\n</implements>\n", dotted);
+        free(dotted);
+    }
 }
 
 /*
@@ -870,8 +994,14 @@
     const DexMethodId* pMethodId;
     const char* backDescriptor;
     const char* name;
-    char* typeDescriptor;
-    char* accessStr;
+    char* typeDescriptor = NULL;
+    char* accessStr = NULL;
+
+    if (gOptions.exportsOnly &&
+        (pDexMethod->accessFlags & (ACC_PUBLIC | ACC_PROTECTED)) == 0)
+    {
+        return;
+    }
 
     pMethodId = dexGetMethodId(pDexFile, pDexMethod->methodIdx);
     name = dexStringById(pDexFile, pMethodId->nameIdx);
@@ -882,22 +1012,119 @@
     accessStr = createAccessFlagStr(pDexMethod->accessFlags,
                     kAccessForMethod);
 
-    printf("    #%d              : (in %s)\n", i, backDescriptor);
-    printf("      name          : '%s'\n", name);
-    printf("      type          : '%s'\n", typeDescriptor);
-    printf("      access        : 0x%04x (%s)\n",
-        pDexMethod->accessFlags, accessStr);
+    if (gOptions.outputFormat == OUTPUT_PLAIN) {
+        printf("    #%d              : (in %s)\n", i, backDescriptor);
+        printf("      name          : '%s'\n", name);
+        printf("      type          : '%s'\n", typeDescriptor);
+        printf("      access        : 0x%04x (%s)\n",
+            pDexMethod->accessFlags, accessStr);
 
-    if (pDexMethod->codeOff == 0) {
-        printf("      code          : (none)\n");
-    } else {
-        printf("      code          -\n");
-        dumpCode(pDexFile, pDexMethod);
+        if (pDexMethod->codeOff == 0) {
+            printf("      code          : (none)\n");
+        } else {
+            printf("      code          -\n");
+            dumpCode(pDexFile, pDexMethod);
+        }
+
+        if (gOptions.disassemble)
+            putchar('\n');
+    } else if (gOptions.outputFormat == OUTPUT_XML) {
+        bool constructor = (name[0] == '<');
+
+        if (constructor) {
+            char* tmp;
+
+            tmp = descriptorClassToDot(backDescriptor);
+            printf("<constructor name=\"%s\"\n", tmp);
+            free(tmp);
+
+            tmp = descriptorToDot(backDescriptor);
+            printf(" type=\"%s\"\n", tmp);
+            free(tmp);
+        } else {
+            printf("<method name=\"%s\"\n", name);
+
+            const char* returnType = strrchr(typeDescriptor, ')');
+            if (returnType == NULL) {
+                fprintf(stderr, "bad method type descriptor '%s'\n",
+                    typeDescriptor);
+                goto bail;
+            }
+
+            char* tmp = descriptorToDot(returnType+1);
+            printf(" return=\"%s\"\n", tmp);
+            free(tmp);
+
+            printf(" abstract=%s\n",
+                quotedBool((pDexMethod->accessFlags & ACC_ABSTRACT) != 0));
+            printf(" native=%s\n",
+                quotedBool((pDexMethod->accessFlags & ACC_NATIVE) != 0));
+
+            bool isSync =
+                (pDexMethod->accessFlags & ACC_SYNCHRONIZED) != 0 ||
+                (pDexMethod->accessFlags & ACC_DECLARED_SYNCHRONIZED) != 0;
+            printf(" synchronized=%s\n", quotedBool(isSync));
+        }
+
+        printf(" static=%s\n",
+            quotedBool((pDexMethod->accessFlags & ACC_STATIC) != 0));
+        printf(" final=%s\n",
+            quotedBool((pDexMethod->accessFlags & ACC_FINAL) != 0));
+        // "deprecated=" not knowable w/o parsing annotations
+        printf(" visibility=%s\n",
+            quotedVisibility(pDexMethod->accessFlags));
+
+        printf(">\n");
+
+        /*
+         * Parameters.
+         */
+        if (typeDescriptor[0] != '(') {
+            fprintf(stderr, "ERROR: bad descriptor '%s'\n", typeDescriptor);
+            goto bail;
+        }
+
+        char tmpBuf[strlen(typeDescriptor)+1];      /* more than big enough */
+        int argNum = 0;
+
+        const char* base = typeDescriptor+1;
+
+        while (*base != ')') {
+            char* cp = tmpBuf;
+
+            while (*base == '[')
+                *cp++ = *base++;
+
+            if (*base == 'L') {
+                /* copy through ';' */
+                do {
+                    *cp = *base++;
+                } while (*cp++ != ';');
+            } else {
+                /* primitive char, copy it */
+                if (strchr("ZBCSIFJD", *base) == NULL) {
+                    fprintf(stderr, "ERROR: bad method signature '%s'\n", base);
+                    goto bail;
+                }
+                *cp++ = *base++;
+            }
+
+            /* null terminate and display */
+            *cp++ = '\0';
+
+            char* tmp = descriptorToDot(tmpBuf);
+            printf("<parameter name=\"arg%d\" type=\"%s\">\n</parameter>\n",
+                argNum++, tmp);
+            free(tmp);
+        }
+
+        if (constructor)
+            printf("</constructor>\n");
+        else
+            printf("</method>\n");
     }
 
-    if (gOptions.disassemble)
-        putchar('\n');
-
+bail:
     free(typeDescriptor);
     free(accessStr);
 }
@@ -913,6 +1140,12 @@
     const char* typeDescriptor;
     char* accessStr;
 
+    if (gOptions.exportsOnly &&
+        (pSField->accessFlags & (ACC_PUBLIC | ACC_PROTECTED)) == 0)
+    {
+        return;
+    }
+
     pFieldId = dexGetFieldId(pDexFile, pSField->fieldIdx);
     name = dexStringById(pDexFile, pFieldId->nameIdx);
     typeDescriptor = dexStringByTypeIdx(pDexFile, pFieldId->typeIdx);
@@ -920,11 +1153,35 @@
 
     accessStr = createAccessFlagStr(pSField->accessFlags, kAccessForField);
 
-    printf("    #%d              : (in %s)\n", i, backDescriptor);
-    printf("      name          : '%s'\n", name);
-    printf("      type          : '%s'\n", typeDescriptor);
-    printf("      access        : 0x%04x (%s)\n",
-        pSField->accessFlags, accessStr);
+    if (gOptions.outputFormat == OUTPUT_PLAIN) {
+        printf("    #%d              : (in %s)\n", i, backDescriptor);
+        printf("      name          : '%s'\n", name);
+        printf("      type          : '%s'\n", typeDescriptor);
+        printf("      access        : 0x%04x (%s)\n",
+            pSField->accessFlags, accessStr);
+    } else if (gOptions.outputFormat == OUTPUT_XML) {
+        char* tmp;
+
+        printf("<field name=\"%s\"\n", name);
+
+        tmp = descriptorToDot(typeDescriptor);
+        printf(" type=\"%s\"\n", tmp);
+        free(tmp);
+
+        printf(" transient=%s\n",
+            quotedBool((pSField->accessFlags & ACC_TRANSIENT) != 0));
+        printf(" volatile=%s\n",
+            quotedBool((pSField->accessFlags & ACC_VOLATILE) != 0));
+        // "value=" not knowable w/o parsing annotations
+        printf(" static=%s\n",
+            quotedBool((pSField->accessFlags & ACC_STATIC) != 0));
+        printf(" final=%s\n",
+            quotedBool((pSField->accessFlags & ACC_FINAL) != 0));
+        // "deprecated=" not knowable w/o parsing annotations
+        printf(" visibility=%s\n",
+            quotedVisibility(pSField->accessFlags));
+        printf(">\n</field>\n");
+    }
 
     free(accessStr);
 }
@@ -934,92 +1191,158 @@
  */
 void dumpIField(const DexFile* pDexFile, const DexField* pIField, int i)
 {
-    const DexFieldId* pFieldId;
-    const char* backDescriptor;
-    const char* name;
-    const char* typeDescriptor;
-    char* accessStr;
-
-    pFieldId = dexGetFieldId(pDexFile, pIField->fieldIdx);
-    name = dexStringById(pDexFile, pFieldId->nameIdx);
-    typeDescriptor = dexStringByTypeIdx(pDexFile, pFieldId->typeIdx);
-    backDescriptor = dexStringByTypeIdx(pDexFile, pFieldId->classIdx);
-
-    accessStr = createAccessFlagStr(pIField->accessFlags, kAccessForField);
-
-    printf("    #%d              : (in %s)\n", i, backDescriptor);
-    printf("      name          : '%s'\n", name);
-    printf("      type          : '%s'\n", typeDescriptor);
-    printf("      access        : 0x%04x (%s)\n",
-        pIField->accessFlags, accessStr);
-
-    free(accessStr);
+    dumpSField(pDexFile, pIField, i);
 }
 
 /*
  * Dump the class.
+ *
+ * If "*pLastPackage" is NULL or does not match the current class' package,
+ * the value will be replaced with a newly-allocated string.
  */
-void dumpClass(DexFile* pDexFile, int idx)
+void dumpClass(DexFile* pDexFile, int idx, char** pLastPackage)
 {
     const DexTypeList* pInterfaces;
     const DexClassDef* pClassDef;
-    DexClassData* pClassData;
+    DexClassData* pClassData = NULL;
     const u1* pEncodedData;
     const char* fileName;
     const char* classDescriptor;
     const char* superclassDescriptor;
-    char* accessStr;
+    char* accessStr = NULL;
     int i;
 
     pClassDef = dexGetClassDef(pDexFile, idx);
-    printf("Class #%d            -\n", idx);
+
+    if (gOptions.exportsOnly && (pClassDef->accessFlags & ACC_PUBLIC) == 0) {
+        //printf("<!-- omitting non-public class %s -->\n",
+        //    classDescriptor);
+        goto bail;
+    }
 
     pEncodedData = dexGetClassData(pDexFile, pClassDef);
     pClassData = dexReadAndVerifyClassData(&pEncodedData, NULL);
 
     if (pClassData == NULL) {
-        printf("Trouble reading class data\n");
-        return;
+        printf("Trouble reading class data (#%d)\n", idx);
+        goto bail;
     }
     
     classDescriptor = dexStringByTypeIdx(pDexFile, pClassDef->classIdx);
-    printf("  Class descriptor  : '%s'\n", classDescriptor);
 
-    accessStr = createAccessFlagStr(pClassDef->accessFlags, kAccessForClass);
-    printf("  Access flags      : 0x%04x (%s)\n",
-        pClassDef->accessFlags, accessStr);
+    /*
+     * For the XML output, show the package name.  Ideally we'd gather
+     * up the classes, sort them, and dump them alphabetically so the
+     * package name wouldn't jump around, but that's not a great plan
+     * for something that needs to run on the device.
+     */
+    if (!(classDescriptor[0] == 'L' &&
+          classDescriptor[strlen(classDescriptor)-1] == ';'))
+    {
+        /* arrays and primitives should not be defined explicitly */
+        fprintf(stderr, "Malformed class name '%s'\n", classDescriptor);
+        /* keep going? */
+    } else if (gOptions.outputFormat == OUTPUT_XML) {
+        char* mangle;
+        char* lastSlash;
+        char* cp;
 
-    if (pClassDef->superclassIdx == kDexNoIndex)
-        superclassDescriptor = "(none)";
-    else {
-        superclassDescriptor =
-            dexStringByTypeIdx(pDexFile, pClassDef->superclassIdx);
-        printf("  Superclass        : '%s'\n", superclassDescriptor);
+        mangle = strdup(classDescriptor + 1);
+        mangle[strlen(mangle)-1] = '\0';
+
+        /* reduce to just the package name */
+        lastSlash = strrchr(mangle, '/');
+        if (lastSlash != NULL) {
+            *lastSlash = '\0';
+        } else {
+            *mangle = '\0';
+        }
+
+        for (cp = mangle; *cp != '\0'; cp++) {
+            if (*cp == '/')
+                *cp = '.';
+        }
+
+        if (*pLastPackage == NULL || strcmp(mangle, *pLastPackage) != 0) {
+            /* start of a new package */
+            if (*pLastPackage != NULL)
+                printf("</package>\n");
+            printf("<package name=\"%s\"\n>\n", mangle);
+            free(*pLastPackage);
+            *pLastPackage = mangle;
+        } else {
+            free(mangle);
+        }
     }
 
-    printf("  Interfaces        -\n");
+    accessStr = createAccessFlagStr(pClassDef->accessFlags, kAccessForClass);
+
+    if (pClassDef->superclassIdx == kDexNoIndex) {
+        superclassDescriptor = NULL;
+    } else {
+        superclassDescriptor =
+            dexStringByTypeIdx(pDexFile, pClassDef->superclassIdx);
+    }
+
+    if (gOptions.outputFormat == OUTPUT_PLAIN) {
+        printf("Class #%d            -\n", idx);
+        printf("  Class descriptor  : '%s'\n", classDescriptor);
+        printf("  Access flags      : 0x%04x (%s)\n",
+            pClassDef->accessFlags, accessStr);
+
+        if (superclassDescriptor != NULL)
+            printf("  Superclass        : '%s'\n", superclassDescriptor);
+
+        printf("  Interfaces        -\n");
+    } else {
+        char* tmp;
+
+        tmp = descriptorClassToDot(classDescriptor);
+        printf("<class name=\"%s\"\n", tmp);
+        free(tmp);
+
+        if (superclassDescriptor != NULL) {
+            tmp = descriptorToDot(superclassDescriptor);
+            printf(" extends=\"%s\"\n", tmp);
+            free(tmp);
+        }
+        printf(" abstract=%s\n",
+            quotedBool((pClassDef->accessFlags & ACC_ABSTRACT) != 0));
+        printf(" static=%s\n",
+            quotedBool((pClassDef->accessFlags & ACC_STATIC) != 0));
+        printf(" final=%s\n",
+            quotedBool((pClassDef->accessFlags & ACC_FINAL) != 0));
+        // "deprecated=" not knowable w/o parsing annotations
+        printf(" visibility=%s\n",
+            quotedVisibility(pClassDef->accessFlags));
+        printf(">\n");
+    }
     pInterfaces = dexGetInterfacesList(pDexFile, pClassDef);
     if (pInterfaces != NULL) {
         for (i = 0; i < (int) pInterfaces->size; i++)
             dumpInterface(pDexFile, dexGetTypeItem(pInterfaces, i), i);
     }
 
-    printf("  Static fields     -\n");
+    if (gOptions.outputFormat == OUTPUT_PLAIN)
+        printf("  Static fields     -\n");
     for (i = 0; i < (int) pClassData->header.staticFieldsSize; i++) {
         dumpSField(pDexFile, &pClassData->staticFields[i], i);
     }
 
-    printf("  Instance fields   -\n");
+    if (gOptions.outputFormat == OUTPUT_PLAIN)
+        printf("  Instance fields   -\n");
     for (i = 0; i < (int) pClassData->header.instanceFieldsSize; i++) {
         dumpIField(pDexFile, &pClassData->instanceFields[i], i);
     }
 
-    printf("  Direct methods    -\n");
+    if (gOptions.outputFormat == OUTPUT_PLAIN)
+        printf("  Direct methods    -\n");
     for (i = 0; i < (int) pClassData->header.directMethodsSize; i++) {
         dumpMethod(pDexFile, &pClassData->directMethods[i], i);
     }
 
-    printf("  Virtual methods   -\n");
+    if (gOptions.outputFormat == OUTPUT_PLAIN)
+        printf("  Virtual methods   -\n");
     for (i = 0; i < (int) pClassData->header.virtualMethodsSize; i++) {
         dumpMethod(pDexFile, &pClassData->virtualMethods[i], i);
     }
@@ -1030,11 +1353,18 @@
         fileName = dexStringById(pDexFile, pClassDef->sourceFileIdx);
     else
         fileName = "unknown";
-    printf("  source_file_idx   : %d (%s)\n",
-        pClassDef->sourceFileIdx, fileName);
 
-    printf("\n");
+    if (gOptions.outputFormat == OUTPUT_PLAIN) {
+        printf("  source_file_idx   : %d (%s)\n",
+            pClassDef->sourceFileIdx, fileName);
+        printf("\n");
+    }
 
+    if (gOptions.outputFormat == OUTPUT_XML) {
+        printf("</class>\n");
+    }
+
+bail:
     free(pClassData);
     free(accessStr);
 }
@@ -1044,20 +1374,35 @@
  */
 void processDexFile(const char* fileName, DexFile* pDexFile)
 {
+    char* package = NULL;
     int i;
 
-    printf("Opened '%s', DEX version '%.3s'\n", fileName,
-        pDexFile->pHeader->magic +4);
+    if (gOptions.verbose) {
+        printf("Opened '%s', DEX version '%.3s'\n", fileName,
+            pDexFile->pHeader->magic +4);
+    }
 
     if (gOptions.showFileHeaders)
         dumpFileHeader(pDexFile);
 
+    if (gOptions.outputFormat == OUTPUT_XML)
+        printf("<api>\n");
+
     for (i = 0; i < (int) pDexFile->pHeader->classDefsSize; i++) {
         if (gOptions.showSectionHeaders)
             dumpClassDef(pDexFile, i);
 
-        dumpClass(pDexFile, i);
+        dumpClass(pDexFile, i, &package);
     }
+
+    /* free the last one allocated */
+    if (package != NULL) {
+        printf("</package>\n");
+        free(package);
+    }
+
+    if (gOptions.outputFormat == OUTPUT_XML)
+        printf("</api>\n");
 }
 
 
@@ -1071,14 +1416,18 @@
     bool mapped = false;
     int result = -1;
 
-    printf("Processing '%s'...\n", fileName);
+    if (gOptions.verbose)
+        printf("Processing '%s'...\n", fileName);
 
     if (dexOpenAndMap(fileName, gOptions.tempFileName, &map, false) != 0)
         goto bail;
     mapped = true;
 
-    pDexFile = dexFileParse(map.addr, map.length,
-        kDexParseVerifyChecksum | kDexParseContinueOnError);
+    int flags = kDexParseVerifyChecksum;
+    if (gOptions.ignoreBadChecksum)
+        flags |= kDexParseContinueOnError;
+
+    pDexFile = dexFileParse(map.addr, map.length, flags);
     if (pDexFile == NULL) {
         fprintf(stderr, "ERROR: DEX parse failed\n");
         goto bail;
@@ -1103,11 +1452,15 @@
 void usage(void)
 {
     fprintf(stderr, "Copyright (C) 2007 The Android Open Source Project\n\n");
-    fprintf(stderr, "%s: [-d] [-f] [-h] [-t tempfile] dexfile...\n", gProgName);
+    fprintf(stderr,
+        "%s: [-d] [-f] [-h] [-i] [-l layout] [-t tempfile] dexfile...\n",
+        gProgName);
     fprintf(stderr, "\n");
     fprintf(stderr, " -d : disassemble code sections\n");
     fprintf(stderr, " -f : display summary information from file header\n");
     fprintf(stderr, " -h : display file header details\n");
+    fprintf(stderr, " -i : ignore checksum failures\n");
+    fprintf(stderr, " -l : output layout, either 'plain' or 'xml'\n");
     fprintf(stderr, " -t : temp file name (defaults to /sdcard/dex-temp-*)\n");
 }
 
@@ -1122,9 +1475,10 @@
     int ic;
 
     memset(&gOptions, 0, sizeof(gOptions));
+    gOptions.verbose = true;
 
     while (1) {
-        ic = getopt(argc, argv, "dfht:");
+        ic = getopt(argc, argv, "dfhil:t:");
         if (ic < 0)
             break;
 
@@ -1138,8 +1492,22 @@
         case 'h':       // dump section headers, i.e. all meta-data
             gOptions.showSectionHeaders = true;
             break;
+        case 'i':       // continue even if checksum is bad
+            gOptions.ignoreBadChecksum = true;
+            break;
+        case 'l':       // layout
+            if (strcmp(optarg, "plain") == 0) {
+                gOptions.outputFormat = OUTPUT_PLAIN;
+            } else if (strcmp(optarg, "xml") == 0) {
+                gOptions.outputFormat = OUTPUT_XML;
+                gOptions.verbose = false;
+                gOptions.exportsOnly = true;
+            } else {
+                wantUsage = true;
+            }
+            break;
         case 't':       // temp file, used when opening compressed Jar
-            gOptions.tempFileName = argv[optind];
+            gOptions.tempFileName = optarg;
             break;
         default:
             wantUsage = true;
@@ -1169,3 +1537,4 @@
 
     return 0;
 }
+
diff --git a/libcore/dalvik/src/main/java/dalvik/system/VMDebug.java b/libcore/dalvik/src/main/java/dalvik/system/VMDebug.java
index 2d09edd..d9f11ce 100644
--- a/libcore/dalvik/src/main/java/dalvik/system/VMDebug.java
+++ b/libcore/dalvik/src/main/java/dalvik/system/VMDebug.java
@@ -153,6 +153,12 @@
         int bufferSize, int flags);
 
     /**
+     * Determine whether method tracing is currently active.
+     * @hide
+     */
+    public static native boolean isMethodTracingActive();
+
+    /**
      * Stops method tracing.
      */
     public static native void stopMethodTracing();
diff --git a/libcore/luni-kernel/src/main/java/java/lang/ClassLoader.java b/libcore/luni-kernel/src/main/java/java/lang/ClassLoader.java
index 822fade..3c2e911 100644
--- a/libcore/luni-kernel/src/main/java/java/lang/ClassLoader.java
+++ b/libcore/luni-kernel/src/main/java/java/lang/ClassLoader.java
@@ -634,7 +634,7 @@
      */
     final boolean isAncestorOf(ClassLoader child) {
         for (ClassLoader current = child; current != null;
-                current = child.parent) {
+                current = current.parent) {
             if (current == this) {
                 return true;
             }
diff --git a/libcore/luni/src/main/native/java_net_InetAddress.cpp b/libcore/luni/src/main/native/java_net_InetAddress.cpp
index cf026bc..0eb2753 100644
--- a/libcore/luni/src/main/native/java_net_InetAddress.cpp
+++ b/libcore/luni/src/main/native/java_net_InetAddress.cpp
@@ -258,14 +258,17 @@
             memset(sin, 0, sizeof(struct sockaddr_in));
             sin->sin_family = AF_INET;
             memcpy(&sin->sin_addr.s_addr, rawAddress, 4);
+            env->ReleaseByteArrayElements(javaAddress, rawAddress, JNI_ABORT);
             break;
         case 16:
             socklen = sizeof(struct sockaddr_in6);
             memset(sin6, 0, sizeof(struct sockaddr_in6));
             sin6->sin6_family = AF_INET6;
             memcpy(&sin6->sin6_addr.s6_addr, rawAddress, 4);
+            env->ReleaseByteArrayElements(javaAddress, rawAddress, JNI_ABORT);
             break;
         default:
+            env->ReleaseByteArrayElements(javaAddress, rawAddress, JNI_ABORT);
             jniThrowException(env, "java/net/UnknownHostException",
                                    "Invalid address length");
             return NULL;
diff --git a/libcore/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp b/libcore/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp
index de01295..f79c019 100755
--- a/libcore/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp
+++ b/libcore/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp
@@ -3084,7 +3084,12 @@
             if ((anOption >> 16) & BROKEN_MULTICAST_IF) {
                 return;
             }
-            result = setsockopt(handle, IPPROTO_IP, IP_MULTICAST_IF, &sockVal, sockSize);
+            struct ip_mreqn mcast_req;
+            memset(&mcast_req, 0, sizeof(mcast_req));
+            memcpy(&(mcast_req.imr_address), &(sockVal.sin_addr),
+                   sizeof(struct in_addr));
+            result = setsockopt(handle, IPPROTO_IP, IP_MULTICAST_IF,
+                                &mcast_req, sizeof(mcast_req));
             if (0 != result) {
                 throwSocketException(env, convertError(errno));
                 return;
diff --git a/libcore/sql/src/main/native/sqlite_jni.c b/libcore/sql/src/main/native/sqlite_jni.c
index c8a76e4..4923869 100644
--- a/libcore/sql/src/main/native/sqlite_jni.c
+++ b/libcore/sql/src/main/native/sqlite_jni.c
@@ -29,6 +29,8 @@
 #define HAVE_BOTH_SQLITE 1
 #endif
 
+#define CANT_PASS_VALIST_AS_CHARPTR
+
 #include "sqlite_jni.h"
 
 #if defined(_WIN32) || !defined(CANT_PASS_VALIST_AS_CHARPTR)
diff --git a/libcore/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLServerSocketImpl.java b/libcore/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLServerSocketImpl.java
index e985908..36282e1 100644
--- a/libcore/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLServerSocketImpl.java
+++ b/libcore/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLServerSocketImpl.java
@@ -146,10 +146,10 @@
         ArrayList<String> array = new ArrayList<String>();
 
         if ((ssl_op_no & SSL_OP_NO_SSLv3) == 0x00000000L) {
-            array.add(supportedProtocols[1]);
+            array.add(supportedProtocols[0]);
         }
         if ((ssl_op_no & SSL_OP_NO_TLSv1) == 0x00000000L) {
-            array.add(supportedProtocols[2]);
+            array.add(supportedProtocols[1]);
         }
         return array.toArray(new String[array.size()]);
     }
diff --git a/libdex/CmdUtils.c b/libdex/CmdUtils.c
index ca1054c..7dfee87 100644
--- a/libdex/CmdUtils.c
+++ b/libdex/CmdUtils.c
@@ -97,14 +97,14 @@
  *
  * If "quiet" is set, don't report common errors.
  *
- * Returns 0 on success.
+ * Returns 0 (kUTFRSuccess) on success.
  */
 UnzipToFileResult dexOpenAndMap(const char* fileName, const char* tempFileName,
     MemMapping* pMap, bool quiet)
 {
-    UnzipToFileResult result = kUTFRSuccess;
+    UnzipToFileResult result = kUTFRGenericFailure;
     int len = strlen(fileName);
-    char tempName[32];
+    char tempNameBuf[32];
     bool removeTemp = false;
     int fd = -1;
 
@@ -125,18 +125,18 @@
              * data to a temp file, the location of which varies.
              */
             if (access("/tmp", W_OK) == 0)
-                sprintf(tempName, "/tmp/dex-temp-%d", getpid());
+                sprintf(tempNameBuf, "/tmp/dex-temp-%d", getpid());
             else
-                sprintf(tempName, "/sdcard/dex-temp-%d", getpid());
+                sprintf(tempNameBuf, "/sdcard/dex-temp-%d", getpid());
 
-            tempFileName = tempName;
+            tempFileName = tempNameBuf;
         }
 
-        result = dexUnzipToFile(fileName, tempName, quiet);
+        result = dexUnzipToFile(fileName, tempFileName, quiet);
         
         if (result == kUTFRSuccess) {
-            //printf("+++ Good unzip to '%s'\n", tempName);
-            fileName = tempName;
+            //printf("+++ Good unzip to '%s'\n", tempFileName);
+            fileName = tempFileName;
             removeTemp = true;
         } else if (result == kUTFRNotZip) {
             if (!quiet) {
@@ -177,8 +177,10 @@
     if (fd >= 0)
         close(fd);
     if (removeTemp) {
-        if (unlink(tempName) != 0)
-            fprintf(stderr, "Warning: unable to remove temp '%s'\n", tempName);
+        if (unlink(tempFileName) != 0) {
+            fprintf(stderr, "Warning: unable to remove temp '%s'\n",
+                tempFileName);
+        }
     }
     return result;
 }
diff --git a/libdex/CmdUtils.h b/libdex/CmdUtils.h
index fa354a9..e0b0105 100644
--- a/libdex/CmdUtils.h
+++ b/libdex/CmdUtils.h
@@ -34,6 +34,7 @@
 /* encode the result of unzipping to a file */
 typedef enum UnzipToFileResult {
     kUTFRSuccess = 0,
+    kUTFRGenericFailure,
     kUTFRBadArgs,
     kUTFRNotZip,
     kUTFRNoClassesDex,
diff --git a/tests/042-new-instance/expected.txt b/tests/042-new-instance/expected.txt
index 1ae2d3b..53447db 100644
--- a/tests/042-new-instance/expected.txt
+++ b/tests/042-new-instance/expected.txt
@@ -1,3 +1,8 @@
 LocalClass succeeded
 Got expected PackageAccess complaint
-LocalClass2 succeeded
+LocalClass3 succeeded
+Got expected InstantationError
+Cons LocalClass failed as expected
+Cons LocalClass2 succeeded
+Cons got expected PackageAccess complaint
+Cons got expected InstantationException
diff --git a/tests/042-new-instance/info.txt b/tests/042-new-instance/info.txt
index 08127da..49c9e02 100644
--- a/tests/042-new-instance/info.txt
+++ b/tests/042-new-instance/info.txt
@@ -1,6 +1,2 @@
-This is a miscellaneous test that was imported into the new-at-the-time
-runtime test framework. The test is intended to exercise basic features,
-and as such cannot be build on top of junit, since failure of such basic
-features might disrupt junit.
-
-TODO: Real description goes here.
+Test various permutations of Class.newInstance and Constructor.newInstance,
+looking for correct handling of access rights and abstract classes.
diff --git a/tests/042-new-instance/src/Main.java b/tests/042-new-instance/src/Main.java
index c77eb48..49894fe 100644
--- a/tests/042-new-instance/src/Main.java
+++ b/tests/042-new-instance/src/Main.java
@@ -1,10 +1,20 @@
 // Copyright 2007 The Android Open Source Project
 
+import java.lang.reflect.Constructor;
+
 /**
  * Test instance creation.
  */
 public class Main {
     public static void main(String[] args) {
+        testClassNewInstance();
+        testConstructorNewInstance();
+    }
+
+    /**
+     * Tests Class.newInstance().
+     */
+    static void testClassNewInstance() {
         // should succeed
         try {
             Class c = Class.forName("LocalClass");
@@ -27,22 +37,89 @@
             ex.printStackTrace();
         }
 
-        LocalClass2.main();
+        LocalClass3.main();
+
+        try {
+            MaybeAbstract ma = new MaybeAbstract();
+            System.err.println("ERROR: MaybeAbstract succeeded unexpectedly");
+        } catch (InstantiationError ie) {
+            System.out.println("Got expected InstantationError");
+        } catch (Exception ex) {
+            System.err.println("Got unexpected MaybeAbstract failure");
+        }
+    }
+
+    /**
+     * Tests Constructor.newInstance().
+     */
+    static void testConstructorNewInstance() {
+        // should fail -- getConstructor only returns public constructors
+        try {
+            Class c = Class.forName("LocalClass");
+            Constructor cons = c.getConstructor(new Class[0] /*(Class[])null*/);
+            System.err.println("Cons LocalClass succeeded unexpectedly");
+        } catch (NoSuchMethodException nsme) {
+            System.out.println("Cons LocalClass failed as expected");
+        } catch (Exception ex) {
+            System.err.println("Cons LocalClass failed strangely");
+            ex.printStackTrace();
+        }
+
+        // should succeed
+        try {
+            Class c = Class.forName("LocalClass2");
+            Constructor cons = c.getConstructor((Class[]) null);
+            Object obj = cons.newInstance();
+            System.out.println("Cons LocalClass2 succeeded");
+        } catch (Exception ex) {
+            System.err.println("Cons LocalClass2 failed");
+            ex.printStackTrace();
+        }
+
+        // should fail
+        try {
+            Class c = Class.forName("otherpackage.PackageAccess");
+            Constructor cons = c.getConstructor(new Class[0] /*(Class[])null*/);
+            System.err.println("ERROR: Cons PackageAccess succeeded unexpectedly");
+        } catch (NoSuchMethodException nsme) {
+            System.out.println("Cons got expected PackageAccess complaint");
+        } catch (Exception ex) {
+            System.err.println("Cons got unexpected PackageAccess failure");
+            ex.printStackTrace();
+        }
+
+        // should fail
+        try {
+            Class c = Class.forName("MaybeAbstract");
+            Constructor cons = c.getConstructor(new Class[0] /*(Class[])null*/);
+            Object obj = cons.newInstance();
+            System.err.println("ERROR: Cons MaybeAbstract succeeded unexpectedly");
+        } catch (InstantiationException ie) {
+            // note InstantiationException vs. InstantiationError
+            System.out.println("Cons got expected InstantationException");
+        } catch (Exception ex) {
+            System.err.println("Cons got unexpected MaybeAbstract failure");
+            ex.printStackTrace();
+        }
     }
 }
 
 class LocalClass {
-  // this class has a default constructor with package visibility
+    // this class has a default constructor with package visibility
+}
+
+class LocalClass2 {
+    public LocalClass2() {}
 }
 
 
-class LocalClass2 {
+class LocalClass3 {
     public static void main() {
         try {
             CC.newInstance();
-            System.out.println("LocalClass2 succeeded");
+            System.out.println("LocalClass3 succeeded");
         } catch (Exception ex) {
-            System.err.println("Got unexpected LocalClass2 failure");
+            System.err.println("Got unexpected LocalClass3 failure");
             ex.printStackTrace();
         }
     }
diff --git a/tests/042-new-instance/src/MaybeAbstract.java b/tests/042-new-instance/src/MaybeAbstract.java
new file mode 100644
index 0000000..43c002b
--- /dev/null
+++ b/tests/042-new-instance/src/MaybeAbstract.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2009 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.
+ */
+
+public /*abstract*/ class MaybeAbstract {
+    public MaybeAbstract() {}
+    int foo() { return 0; }
+}
+
diff --git a/tests/042-new-instance/src2/MaybeAbstract.java b/tests/042-new-instance/src2/MaybeAbstract.java
new file mode 100644
index 0000000..bfbfd45
--- /dev/null
+++ b/tests/042-new-instance/src2/MaybeAbstract.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2009 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.
+ */
+
+public abstract class MaybeAbstract {
+    public MaybeAbstract() {}
+    int foo() { return 0; }
+}
+
diff --git a/vm/Android.mk b/vm/Android.mk
index 25a03fd..f3eed3f 100644
--- a/vm/Android.mk
+++ b/vm/Android.mk
@@ -41,42 +41,46 @@
   LOCAL_CFLAGS += -DWITH_MONITOR_TRACKING
 endif
 
-#
-# "Debug" profile:
-# - debugger enabled
-# - profiling enabled
-# - tracked-reference verification enabled
-# - allocation limits enabled
-# - GDB helpers enabled
-# - LOGV
-# - assert()  (NDEBUG is handled in the build system)
-#
-ifeq ($(TARGET_BUILD_TYPE),debug)
-LOCAL_CFLAGS += -DWITH_INSTR_CHECKS -DWITH_EXTRA_OBJECT_VALIDATION
-LOCAL_CFLAGS += -DWITH_TRACKREF_CHECKS
-LOCAL_CFLAGS += -DWITH_ALLOC_LIMITS
-#LOCAL_CFLAGS += -DCHECK_MUTEX
-#LOCAL_CFLAGS += -DPROFILE_FIELD_ACCESS
-LOCAL_CFLAGS += -DDVM_SHOW_EXCEPTION=3
-# add some extra stuff to make it easier to examine with GDB
-LOCAL_CFLAGS += -DEASY_GDB
+# Make DEBUG_DALVIK_VM default to true when building the simulator.
+ifeq ($(TARGET_SIMULATOR),true)
+  ifeq ($(strip $(DEBUG_DALVIK_VM)),)
+    DEBUG_DALVIK_VM := true
+  endif
 endif
 
-
-#
-# "Performance" profile:
-# - all development features disabled
-# - compiler optimizations enabled (redundant for "release" builds)
-# - (debugging and profiling still enabled)
-#
-ifeq ($(TARGET_BUILD_TYPE),release)
-#LOCAL_CFLAGS += -DNDEBUG -DLOG_NDEBUG=1
-# "-O2" is redundant for device (release) but useful for sim (debug)
-#LOCAL_CFLAGS += -O2 -Winline
-LOCAL_CFLAGS += -DDVM_SHOW_EXCEPTION=1
-# if you want to try with assertions on the device, add:
-#LOCAL_CFLAGS += -UNDEBUG -DDEBUG=1 -DLOG_NDEBUG=1 -DWITH_DALVIK_ASSERT
-endif
+ifeq ($(strip $(DEBUG_DALVIK_VM)),true)
+  #
+  # "Debug" profile:
+  # - debugger enabled
+  # - profiling enabled
+  # - tracked-reference verification enabled
+  # - allocation limits enabled
+  # - GDB helpers enabled
+  # - LOGV
+  # - assert()  (NDEBUG is handled in the build system)
+  #
+  LOCAL_CFLAGS += -DWITH_INSTR_CHECKS -DWITH_EXTRA_OBJECT_VALIDATION
+  LOCAL_CFLAGS += -DWITH_TRACKREF_CHECKS
+  LOCAL_CFLAGS += -DWITH_ALLOC_LIMITS
+  #LOCAL_CFLAGS += -DCHECK_MUTEX
+  #LOCAL_CFLAGS += -DPROFILE_FIELD_ACCESS
+  LOCAL_CFLAGS += -DDVM_SHOW_EXCEPTION=3
+  # add some extra stuff to make it easier to examine with GDB
+  LOCAL_CFLAGS += -DEASY_GDB
+else  # !DALVIK_VM_DEBUG
+  #
+  # "Performance" profile:
+  # - all development features disabled
+  # - compiler optimizations enabled (redundant for "release" builds)
+  # - (debugging and profiling still enabled)
+  #
+  #LOCAL_CFLAGS += -DNDEBUG -DLOG_NDEBUG=1
+  # "-O2" is redundant for device (release) but useful for sim (debug)
+  #LOCAL_CFLAGS += -O2 -Winline
+  LOCAL_CFLAGS += -DDVM_SHOW_EXCEPTION=1
+  # if you want to try with assertions on the device, add:
+  #LOCAL_CFLAGS += -UNDEBUG -DDEBUG=1 -DLOG_NDEBUG=1 -DWITH_DALVIK_ASSERT
+endif  # !DALVIK_VM_DEBUG
 
 # bug hunting: checksum and verify interpreted stack when making JNI calls
 #LOCAL_CFLAGS += -DWITH_JNI_STACK_CHECK
diff --git a/vm/CheckJni.c b/vm/CheckJni.c
index 4791a01..0601e72 100644
--- a/vm/CheckJni.c
+++ b/vm/CheckJni.c
@@ -84,6 +84,8 @@
 
 #define CHECK_FIELD_TYPE(_obj, _fieldid, _prim, _isstatic)                  \
     checkFieldType(_obj, _fieldid, _prim, _isstatic, __FUNCTION__)
+#define CHECK_INST_FIELD_ID(_env, _obj, _fieldid)                           \
+    checkInstanceFieldID(_env, _obj, _fieldid, __FUNCTION__)
 #define CHECK_CLASS(_env, _clazz)                                           \
     checkClass(_env, _clazz, __FUNCTION__)
 #define CHECK_STRING(_env, _str)                                            \
@@ -638,8 +640,15 @@
 /*
  * Verify that this instance field ID is valid for this object.
  */
-static void checkInstanceFieldID(JNIEnv* env, jobject obj, jfieldID fieldID)
+static void checkInstanceFieldID(JNIEnv* env, jobject obj, jfieldID fieldID,
+    const char* func)
 {
+    if (obj == NULL) {
+        LOGW("JNI WARNING: invalid null object (%s)\n", func);
+        abortMaybe();
+        return;
+    }
+
     ClassObject* clazz = ((Object*)obj)->clazz;
 
     /*
@@ -736,22 +745,35 @@
 /*
  * Verify the guard area and, if "modOkay" is false, that the data itself
  * has not been altered.
+ *
+ * The caller has already checked that "dataBuf" is non-NULL.
  */
 static bool checkGuardedCopy(const void* dataBuf, bool modOkay)
 {
+    static const u4 kMagicCmp = kGuardMagic;
     const u1* fullBuf = ((const u1*) dataBuf) - kGuardLen / 2;
     const GuardExtra* pExtra = getGuardExtra(dataBuf);
-    size_t len = pExtra->originalLen;
+    size_t len;
     const u2* pat;
     int i;
 
-    if (pExtra->magic != kGuardMagic) {
-        LOGE("JNI: guard magic does not match (found 0x%08x) "
+    /*
+     * Before we do anything with "pExtra", check the magic number.  We
+     * do the check with memcmp rather than "==" in case the pointer is
+     * unaligned.  If it points to completely bogus memory we're going
+     * to crash, but there's no easy way around that.
+     */
+    if (memcmp(&pExtra->magic, &kMagicCmp, 4) != 0) {
+        u1 buf[4];
+        memcpy(buf, &pExtra->magic, 4);
+        LOGE("JNI: guard magic does not match (found 0x%02x%02x%02x%02x) "
              "-- incorrect data pointer %p?\n",
-            pExtra->magic, dataBuf);
+            buf[3], buf[2], buf[1], buf[0], dataBuf); /* assume little endian */
         return false;
     }
 
+    len = pExtra->originalLen;
+
     /* check bottom half of guard; skip over optional checksum storage */
     pat = (u2*) fullBuf;
     for (i = kGuardExtra / 2; i < (int) (kGuardLen / 2 - kGuardExtra) / 2; i++)
@@ -889,6 +911,7 @@
     if (!checkGuardedCopy(dataBuf, true)) {
         LOGE("JNI: failed guarded copy check in releaseGuardedPACopy\n");
         abortMaybe();
+        return NULL;
     }
 
     switch (mode) {
@@ -1328,7 +1351,7 @@
         CHECK_ENTER(env, kFlag_Default);                                    \
         CHECK_OBJECT(env, obj);                                             \
         _ctype result;                                                      \
-        checkInstanceFieldID(env, obj, fieldID);                            \
+        CHECK_INST_FIELD_ID(env, obj, fieldID);                             \
         result = BASE_ENV(env)->Get##_jname##Field(env, obj, fieldID);      \
         CHECK_EXIT(env);                                                    \
         return result;                                                      \
@@ -1349,7 +1372,7 @@
     {                                                                       \
         CHECK_ENTER(env, kFlag_Default);                                    \
         CHECK_OBJECT(env, obj);                                             \
-        checkInstanceFieldID(env, obj, fieldID);                            \
+        CHECK_INST_FIELD_ID(env, obj, fieldID);                             \
         CHECK_FIELD_TYPE((jobject)(u4) value, fieldID, _ftype, false);      \
         BASE_ENV(env)->Set##_jname##Field(env, obj, fieldID, value);        \
         CHECK_EXIT(env);                                                    \
@@ -1571,6 +1594,7 @@
         if (!checkGuardedCopy(chars, false)) {
             LOGE("JNI: failed guarded copy check in ReleaseStringChars\n");
             abortMaybe();
+            return;
         }
         chars = (const jchar*) freeGuardedCopy((jchar*)chars);
     }
@@ -1626,6 +1650,7 @@
         if (!checkGuardedCopy(utf, false)) {
             LOGE("JNI: failed guarded copy check in ReleaseStringUTFChars\n");
             abortMaybe();
+            return;
         }
         utf = (const char*) freeGuardedCopy((char*)utf);
     }
@@ -1892,6 +1917,7 @@
         if (!checkGuardedCopy(carray, false)) {
             LOGE("JNI: failed guarded copy check in ReleaseStringCritical\n");
             abortMaybe();
+            return;
         }
         carray = (const jchar*) freeGuardedCopy((jchar*)carray);
     }
@@ -1945,6 +1971,7 @@
         LOGW("JNI WARNING: invalid values for address (%p) or capacity (%ld)\n",
             address, (long) capacity);
         abortMaybe();
+        return NULL;
     }
     result = BASE_ENV(env)->NewDirectByteBuffer(env, address, capacity);
     CHECK_EXIT(env);
diff --git a/vm/Globals.h b/vm/Globals.h
index 2ac73ce..79b9e91 100644
--- a/vm/Globals.h
+++ b/vm/Globals.h
@@ -144,6 +144,13 @@
     volatile int classSerialNumber;
 
     /*
+     * Classes with a low classSerialNumber are probably in the zygote, and
+     * their InitiatingLoaderList is not used, to promote sharing. The list is
+     * kept here instead.
+     */
+    InitiatingLoaderList* initiatingLoaderList;
+
+    /*
      * Interned strings.
      */
     HashTable*  internedStrings;
diff --git a/vm/Profile.c b/vm/Profile.c
index 9b47885..6055580 100644
--- a/vm/Profile.c
+++ b/vm/Profile.c
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 /*
  * Android's method call profiling goodies.
  */
@@ -28,10 +29,10 @@
 #include <sys/mman.h>
 #include <sched.h>
 #include <errno.h>
+#include <fcntl.h>
 
 #ifdef HAVE_ANDROID_OS
 # define UPDATE_MAGIC_PAGE      1
-# define MAGIC_PAGE_BASE_ADDR   0x08000000
 # ifndef PAGESIZE
 #  define PAGESIZE              4096
 # endif
@@ -176,13 +177,20 @@
      * We could key this off of the "ro.kernel.qemu" property, but there's
      * no real harm in doing this on a real device.
      */
-    gDvm.emulatorTracePage = mmap((void*) MAGIC_PAGE_BASE_ADDR,
-        PAGESIZE, PROT_READ|PROT_WRITE, MAP_FIXED|MAP_SHARED|MAP_ANON, -1, 0);
-    if (gDvm.emulatorTracePage == MAP_FAILED) {
-        LOGE("Unable to mmap magic page (0x%08x)\n", MAGIC_PAGE_BASE_ADDR);
-        return false;
+    int fd = open("/dev/qemu_trace", O_RDWR);
+    if (fd < 0) {
+        LOGV("Unable to open /dev/qemu_trace\n");
+    } else {
+        gDvm.emulatorTracePage = mmap(0, PAGESIZE, PROT_READ|PROT_WRITE,
+                                      MAP_SHARED, fd, 0);
+        close(fd);
+        if (gDvm.emulatorTracePage == MAP_FAILED) {
+            LOGE("Unable to mmap /dev/qemu_trace\n");
+            gDvm.emulatorTracePage = NULL;
+        } else {
+            *(u4*) gDvm.emulatorTracePage = 0;
+        }
     }
-    *(u4*) gDvm.emulatorTracePage = 0;
 #else
     assert(gDvm.emulatorTracePage == NULL);
 #endif
@@ -388,6 +396,7 @@
     return;
 
 fail:
+    updateActiveProfilers(-1);
     if (state->traceFile != NULL) {
         fclose(state->traceFile);
         state->traceFile = NULL;
@@ -448,6 +457,15 @@
 }
 
 /*
+ * Returns "true" if method tracing is currently active.
+ */
+bool dvmIsMethodTraceActive(void)
+{
+    const MethodTraceState* state = &gDvm.methodTrace;
+    return state->traceEnabled;
+}
+
+/*
  * Stop method tracing.  We write the buffer to disk and generate a key
  * file so we can interpret it.
  */
@@ -464,6 +482,7 @@
 
     if (!state->traceEnabled) {
         /* somebody already stopped it, or it was never started */
+        LOGD("TRACE stop requested, but not running\n");
         dvmUnlockMutex(&state->startStopLock);
         return;
     } else {
@@ -627,7 +646,7 @@
         return;
     assert(method->insns != NULL);
 
-    u4* pMagic = ((u4*) MAGIC_PAGE_BASE_ADDR) +1;
+    u4* pMagic = (u4*) gDvm.emulatorTracePage;
 
     /*
      * The dexlist output shows the &DexCode.insns offset value, which
@@ -690,6 +709,10 @@
  */
 void dvmEmulatorTraceStart(void)
 {
+    /* If we could not map the emulator trace page, then do not enable tracing */
+    if (gDvm.emulatorTracePage == NULL)
+        return;
+
     updateActiveProfilers(1);
 
     /* in theory we should make this an atomic inc; in practice not important */
@@ -705,7 +728,7 @@
 {
     if (gDvm.emulatorTraceEnableCount == 0) {
         LOGE("ERROR: emulator tracing not enabled\n");
-        dvmAbort();
+        return;
     }
     updateActiveProfilers(-1);
     /* in theory we should make this an atomic inc; in practice not important */
diff --git a/vm/Profile.h b/vm/Profile.h
index f762974..cdaf027 100644
--- a/vm/Profile.h
+++ b/vm/Profile.h
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 /*
  * Android's method call profiling goodies.
  */
@@ -96,6 +97,7 @@
  * Start/stop method tracing.
  */
 void dvmMethodTraceStart(const char* traceFileName, int bufferSize, int flags);
+bool dvmIsMethodTraceActive(void);
 void dvmMethodTraceStop(void);
 
 /*
diff --git a/vm/Thread.c b/vm/Thread.c
index 42b527e..acfc7a9 100644
--- a/vm/Thread.c
+++ b/vm/Thread.c
@@ -43,6 +43,9 @@
 #undef __KERNEL__
 #endif
 
+// Change this to enable logging on cgroup errors
+#define ENABLE_CGROUP_ERR_LOGGING 0
+
 // change this to LOGV/LOGD to debug thread activity
 #define LOG_THREAD  LOGVV
 
@@ -624,6 +627,7 @@
 /*
  * Finish preparing the main thread, allocating some objects to represent
  * it.  As part of doing so, we finish initializing Thread and ThreadGroup.
+ * This will execute some interpreted code (e.g. class initializers).
  */
 bool dvmPrepMainThread(void)
 {
@@ -711,7 +715,8 @@
 
     /*
      * Stuff the VMThread back into the Thread.  From this point on, other
-     * Threads will see that this Thread is running.
+     * Threads will see that this Thread is running (at least, they would,
+     * if there were any).
      */
     dvmSetFieldObject(threadObj, gDvm.offJavaLangThread_vmThread,
         vmThreadObj);
@@ -719,6 +724,24 @@
     thread->threadObj = threadObj;
 
     /*
+     * Set the context class loader.  This invokes a ClassLoader method,
+     * which could conceivably call Thread.currentThread(), so we want the
+     * Thread to be fully configured before we do this.
+     */
+    Object* systemLoader = dvmGetSystemClassLoader();
+    if (systemLoader == NULL) {
+        LOGW("WARNING: system class loader is NULL (setting main ctxt)\n");
+        /* keep going */
+    }
+    int ctxtClassLoaderOffset = dvmFindFieldOffset(gDvm.classJavaLangThread,
+        "contextClassLoader", "Ljava/lang/ClassLoader;");
+    if (ctxtClassLoaderOffset < 0) {
+        LOGE("Unable to find contextClassLoader field in Thread\n");
+        return false;
+    }
+    dvmSetFieldObject(threadObj, ctxtClassLoaderOffset, systemLoader);
+
+    /*
      * Finish our thread prep.
      */
 
@@ -2745,6 +2768,41 @@
 };
 
 /*
+ * Change the scheduler cgroup of a pid
+ */
+int dvmChangeThreadSchedulerGroup(const char *cgroup)
+{
+#ifdef HAVE_ANDROID_OS
+    FILE *fp;
+    char path[255];
+    int rc;
+
+    sprintf(path, "/dev/cpuctl/%s/tasks", (cgroup ? cgroup : ""));
+
+    if (!(fp = fopen(path, "w"))) {
+#if ENABLE_CGROUP_ERR_LOGGING
+        LOGW("Unable to open %s (%s)\n", path, strerror(errno));
+#endif
+        return -errno;
+    }
+
+    rc = fprintf(fp, "0");
+    fclose(fp);
+
+    if (rc < 0) {
+#if ENABLE_CGROUP_ERR_LOGGING
+        LOGW("Unable to move pid %d to cgroup %s (%s)\n", getpid(),
+             (cgroup ? cgroup : "<default>"), strerror(errno));
+#endif
+    }
+
+    return (rc < 0) ? errno : 0;
+#else // HAVE_ANDROID_OS
+    return 0;
+#endif
+}
+
+/*
  * Change the priority of a system thread to match that of the Thread object.
  *
  * We map a priority value from 1-10 to Linux "nice" values, where lower
@@ -2761,6 +2819,12 @@
     }
     newNice = kNiceValues[newPriority-1];
 
+    if (newPriority == ANDROID_PRIORITY_BACKGROUND) {
+        dvmChangeThreadSchedulerGroup("bg_non_interactive");
+    } else if (getpriority(PRIO_PROCESS, pid) == ANDROID_PRIORITY_BACKGROUND) {
+        dvmChangeThreadSchedulerGroup(NULL);
+    }
+
     if (setpriority(PRIO_PROCESS, pid, newNice) != 0) {
         char* str = dvmGetThreadName(thread);
         LOGI("setPriority(%d) '%s' to prio=%d(n=%d) failed: %s\n",
diff --git a/vm/Thread.h b/vm/Thread.h
index b64f9b7..86a7845 100644
--- a/vm/Thread.h
+++ b/vm/Thread.h
@@ -398,6 +398,11 @@
 INLINE void dvmSetThreadJNIEnv(Thread* self, JNIEnv* env) { self->jniEnv = env;}
 
 /*
+ * Change the scheduler group of the current process
+ */
+int dvmChangeThreadSchedulerGroup(const char *group);
+
+/*
  * Update the priority value of the underlying pthread.
  */
 void dvmChangeThreadPriority(Thread* thread, int newPriority);
diff --git a/vm/alloc/Heap.c b/vm/alloc/Heap.c
index 9ddc8be..09954ea 100644
--- a/vm/alloc/Heap.c
+++ b/vm/alloc/Heap.c
@@ -774,6 +774,11 @@
         /* Current value is numerically greater than "normal", which
          * in backward UNIX terms means lower priority.
          */
+
+        if (priorityResult == ANDROID_PRIORITY_BACKGROUND) {
+            dvmChangeThreadSchedulerGroup(NULL);
+        }
+
         if (setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_NORMAL) != 0) {
             LOGI_HEAP("Unable to elevate priority from %d to %d\n",
                 priorityResult, ANDROID_PRIORITY_NORMAL);
@@ -831,6 +836,8 @@
     if (gcHeap->hprofDumpOnGc) {
         char nameBuf[128];
 
+        gcHeap->hprofResult = -1;
+
         if (gcHeap->hprofFileName == NULL) {
             /* no filename was provided; invent one */
             sprintf(nameBuf, "/data/misc/heap-dump-tm%d-pid%d.hprof",
@@ -982,7 +989,8 @@
     if (gcHeap->hprofContext != NULL) {
         hprofFinishHeapDump(gcHeap->hprofContext);
 //TODO: write a HEAP_SUMMARY record
-        hprofShutdown(gcHeap->hprofContext);
+        if (hprofShutdown(gcHeap->hprofContext))
+            gcHeap->hprofResult = 0;    /* indicate success */
         gcHeap->hprofContext = NULL;
     }
 #endif
@@ -1016,6 +1024,10 @@
         } else {
             LOGD_HEAP("Reset priority to %d\n", oldThreadPriority);
         }
+
+        if (oldThreadPriority == ANDROID_PRIORITY_BACKGROUND) {
+            dvmChangeThreadSchedulerGroup("bg_non_interactive");
+        }
     }
     gcElapsedTime = (dvmGetRelativeTimeUsec() - gcHeap->gcStartTime) / 1000;
     if (gcElapsedTime < 10000) {
@@ -1046,16 +1058,23 @@
  * Perform garbage collection, writing heap information to the specified file.
  *
  * If "fileName" is NULL, a suitable name will be generated automatically.
+ *
+ * Returns 0 on success, or an error code on failure.
  */
-void hprofDumpHeap(const char* fileName)
+int hprofDumpHeap(const char* fileName)
 {
+    int result;
+
     dvmLockMutex(&gDvm.gcHeapLock);
 
     gDvm.gcHeap->hprofDumpOnGc = true;
     gDvm.gcHeap->hprofFileName = fileName;
     dvmCollectGarbageInternal(false);
+    result = gDvm.gcHeap->hprofResult;
 
     dvmUnlockMutex(&gDvm.gcHeapLock);
+
+    return result;
 }
 
 void dvmHeapSetHprofGcScanState(hprof_heap_tag_t state, u4 threadSerialNumber)
diff --git a/vm/alloc/HeapInternal.h b/vm/alloc/HeapInternal.h
index 7851983..fafb87a 100644
--- a/vm/alloc/HeapInternal.h
+++ b/vm/alloc/HeapInternal.h
@@ -189,6 +189,7 @@
     bool            hprofDumpOnGc;
     const char*     hprofFileName;
     hprof_context_t *hprofContext;
+    int             hprofResult;
 #endif
 };
 
diff --git a/vm/analysis/CodeVerify.c b/vm/analysis/CodeVerify.c
index 65aa833..8c5e8d2 100644
--- a/vm/analysis/CodeVerify.c
+++ b/vm/analysis/CodeVerify.c
@@ -5163,23 +5163,20 @@
         if (!checkMoveException(meth, insnIdx+insnWidth, "next"))
             goto bail;
 
-        /*
-         * We want to update the registers and set the "changed" flag on the
-         * next instruction (if necessary).  We may not be storing register
-         * changes for all addresses, so for non-branch targets we just
-         * compare "entry" vs. "work" to see if we've changed anything.
-         */
         if (getRegisterLine(regTable, insnIdx+insnWidth) != NULL) {
+            /*
+             * Merge registers into what we have for the next instruction,
+             * and set the "changed" flag if needed.
+             */
             updateRegisters(meth, insnFlags, regTable, insnIdx+insnWidth,
                 workRegs);
         } else {
-            /* if not yet visited, or regs were updated, set "changed" */
-            if (!dvmInsnIsVisited(insnFlags, insnIdx+insnWidth) ||
-                compareRegisters(workRegs, entryRegs,
-                    insnRegCount + kExtraRegs) != 0)
-            {
-                dvmInsnSetChanged(insnFlags, insnIdx+insnWidth, true);
-            }
+            /*
+             * We're not recording register data for the next instruction,
+             * so we don't know what the prior state was.  We have to
+             * assume that something has changed and re-evaluate it.
+             */
+            dvmInsnSetChanged(insnFlags, insnIdx+insnWidth, true);
         }
     }
 
diff --git a/vm/hprof/Hprof.c b/vm/hprof/Hprof.c
index 66b46f4..2e6f7c9 100644
--- a/vm/hprof/Hprof.c
+++ b/vm/hprof/Hprof.c
@@ -111,7 +111,10 @@
     }
 }
 
-void
+/*
+ * Finish up the hprof dump.  Returns true on success.
+ */
+bool
 hprofShutdown(hprof_context_t *ctx)
 {
     FILE *tempFp = ctx->fp;
@@ -131,7 +134,7 @@
         fclose(tempFp);
         free(ctx->fileName);
         free(ctx);
-        return;
+        return false;
     }
     hprofContextInit(ctx, ctx->fileName, fp, true);
 
@@ -179,4 +182,5 @@
 
     /* throw out a log message for the benefit of "runhat" */
     LOGI("hprof: heap dump completed, temp file removed\n");
+    return true;
 }
diff --git a/vm/hprof/Hprof.h b/vm/hprof/Hprof.h
index e0e2d4b..696b0a7 100644
--- a/vm/hprof/Hprof.h
+++ b/vm/hprof/Hprof.h
@@ -235,7 +235,7 @@
  */
 
 hprof_context_t *hprofStartup(const char *outputFileName);
-void hprofShutdown(hprof_context_t *ctx);
+bool hprofShutdown(hprof_context_t *ctx);
 
 /*
  * Heap.c functions
@@ -244,7 +244,7 @@
  * the heap implementation; these functions require heap knowledge,
  * so they are implemented in Heap.c.
  */
-void hprofDumpHeap(const char* fileName);
+int hprofDumpHeap(const char* fileName);
 void dvmHeapSetHprofGcScanState(hprof_heap_tag_t state, u4 threadSerialNumber);
 
 #endif  // _DALVIK_HPROF_HPROF
diff --git a/vm/mterp/armv4/OP_AGET_WIDE.S b/vm/mterp/armv4t/OP_AGET_WIDE.S
similarity index 100%
rename from vm/mterp/armv4/OP_AGET_WIDE.S
rename to vm/mterp/armv4t/OP_AGET_WIDE.S
diff --git a/vm/mterp/armv4/OP_APUT_WIDE.S b/vm/mterp/armv4t/OP_APUT_WIDE.S
similarity index 100%
rename from vm/mterp/armv4/OP_APUT_WIDE.S
rename to vm/mterp/armv4t/OP_APUT_WIDE.S
diff --git a/vm/mterp/armv4/OP_IGET_WIDE.S b/vm/mterp/armv4t/OP_IGET_WIDE.S
similarity index 100%
rename from vm/mterp/armv4/OP_IGET_WIDE.S
rename to vm/mterp/armv4t/OP_IGET_WIDE.S
diff --git a/vm/mterp/armv4/OP_IGET_WIDE_QUICK.S b/vm/mterp/armv4t/OP_IGET_WIDE_QUICK.S
similarity index 100%
rename from vm/mterp/armv4/OP_IGET_WIDE_QUICK.S
rename to vm/mterp/armv4t/OP_IGET_WIDE_QUICK.S
diff --git a/vm/mterp/armv4/OP_IPUT_WIDE.S b/vm/mterp/armv4t/OP_IPUT_WIDE.S
similarity index 100%
rename from vm/mterp/armv4/OP_IPUT_WIDE.S
rename to vm/mterp/armv4t/OP_IPUT_WIDE.S
diff --git a/vm/mterp/armv4/OP_IPUT_WIDE_QUICK.S b/vm/mterp/armv4t/OP_IPUT_WIDE_QUICK.S
similarity index 100%
rename from vm/mterp/armv4/OP_IPUT_WIDE_QUICK.S
rename to vm/mterp/armv4t/OP_IPUT_WIDE_QUICK.S
diff --git a/vm/mterp/armv4/OP_SGET_WIDE.S b/vm/mterp/armv4t/OP_SGET_WIDE.S
similarity index 100%
rename from vm/mterp/armv4/OP_SGET_WIDE.S
rename to vm/mterp/armv4t/OP_SGET_WIDE.S
diff --git a/vm/mterp/armv4/OP_SPUT_WIDE.S b/vm/mterp/armv4t/OP_SPUT_WIDE.S
similarity index 100%
rename from vm/mterp/armv4/OP_SPUT_WIDE.S
rename to vm/mterp/armv4t/OP_SPUT_WIDE.S
diff --git a/vm/mterp/armv4/platform.S b/vm/mterp/armv4t/platform.S
similarity index 100%
rename from vm/mterp/armv4/platform.S
rename to vm/mterp/armv4t/platform.S
diff --git a/vm/mterp/config-armv4 b/vm/mterp/config-armv4t
similarity index 80%
rename from vm/mterp/config-armv4
rename to vm/mterp/config-armv4t
index 4f64c11..01eddb2 100644
--- a/vm/mterp/config-armv4
+++ b/vm/mterp/config-armv4t
@@ -13,8 +13,8 @@
 # limitations under the License.
 
 #
-# Configuration for ARMv4 architecture targets.  This is largely pulled
-# from the ARMv5 sources, but we can't use certain instructions introduced
+# Configuration for ARMv4T architecture targets.  This is largely pulled
+# from the ARMv5TE sources, but we can't use certain instructions introduced
 # in ARMv5 (BLX, CLZ, LDC2, MCR2, MRC2, STC2) or ARMv5TE (PLD, LDRD, MCRR,
 # MRRC, QADD, QDADD, QDSUB, QSUB, SMLA, SMLAL, SMLAW, SMUL, SMULW, STRD).
 #
@@ -42,14 +42,14 @@
 
 # opcode list; argument to op-start is default directory
 op-start armv5te
-    op OP_AGET_WIDE armv4
-    op OP_APUT_WIDE armv4
-    op OP_IGET_WIDE armv4
-    op OP_IGET_WIDE_QUICK armv4
-    op OP_IPUT_WIDE armv4
-    op OP_IPUT_WIDE_QUICK armv4
-    op OP_SGET_WIDE armv4
-    op OP_SPUT_WIDE armv4
+    op OP_AGET_WIDE armv4t
+    op OP_APUT_WIDE armv4t
+    op OP_IGET_WIDE armv4t
+    op OP_IGET_WIDE_QUICK armv4t
+    op OP_IPUT_WIDE armv4t
+    op OP_IPUT_WIDE_QUICK armv4t
+    op OP_SGET_WIDE armv4t
+    op OP_SPUT_WIDE armv4t
 op-end
 
 # "helper" code for C; include if you use any of the C stubs (this generates
diff --git a/vm/mterp/out/InterpAsm-armv4.S b/vm/mterp/out/InterpAsm-armv4t.S
similarity index 99%
rename from vm/mterp/out/InterpAsm-armv4.S
rename to vm/mterp/out/InterpAsm-armv4t.S
index 3de7aea..d60571b 100644
--- a/vm/mterp/out/InterpAsm-armv4.S
+++ b/vm/mterp/out/InterpAsm-armv4t.S
@@ -1,5 +1,5 @@
 /*
- * This file was generated automatically by gen-mterp.py for 'armv4'.
+ * This file was generated automatically by gen-mterp.py for 'armv4t'.
  *
  * --> DO NOT EDIT <--
  */
@@ -1855,7 +1855,7 @@
 /* ------------------------------ */
     .balign 64
 .L_OP_AGET_WIDE: /* 0x45 */
-/* File: armv4/OP_AGET_WIDE.S */
+/* File: armv4t/OP_AGET_WIDE.S */
     /*
      * Array get, 64 bits.  vAA <- vBB[vCC].
      *
@@ -2078,7 +2078,7 @@
 /* ------------------------------ */
     .balign 64
 .L_OP_APUT_WIDE: /* 0x4c */
-/* File: armv4/OP_APUT_WIDE.S */
+/* File: armv4t/OP_APUT_WIDE.S */
     /*
      * Array put, 64 bits.  vBB[vCC] <- vAA.
      */
@@ -2289,7 +2289,7 @@
 /* ------------------------------ */
     .balign 64
 .L_OP_IGET_WIDE: /* 0x53 */
-/* File: armv4/OP_IGET_WIDE.S */
+/* File: armv4t/OP_IGET_WIDE.S */
     /*
      * Wide 32-bit instance field get.
      */
@@ -2483,7 +2483,7 @@
 /* ------------------------------ */
     .balign 64
 .L_OP_IPUT_WIDE: /* 0x5a */
-/* File: armv4/OP_IPUT_WIDE.S */
+/* File: armv4t/OP_IPUT_WIDE.S */
     /* iput-wide vA, vB, field@CCCC */
     mov     r0, rINST, lsr #12          @ r0<- B
     ldr     r3, [rGLUE, #offGlue_methodClassDex]    @ r3<- DvmDex
@@ -2672,7 +2672,7 @@
 /* ------------------------------ */
     .balign 64
 .L_OP_SGET_WIDE: /* 0x61 */
-/* File: armv4/OP_SGET_WIDE.S */
+/* File: armv4t/OP_SGET_WIDE.S */
     /*
      * 64-bit SGET handler.
      */
@@ -2850,7 +2850,7 @@
 /* ------------------------------ */
     .balign 64
 .L_OP_SPUT_WIDE: /* 0x68 */
-/* File: armv4/OP_SPUT_WIDE.S */
+/* File: armv4t/OP_SPUT_WIDE.S */
     /*
      * 64-bit SPUT handler.
      */
@@ -7522,7 +7522,7 @@
 /* ------------------------------ */
     .balign 64
 .L_OP_IGET_WIDE_QUICK: /* 0xf3 */
-/* File: armv4/OP_IGET_WIDE_QUICK.S */
+/* File: armv4t/OP_IGET_WIDE_QUICK.S */
     /* iget-wide-quick vA, vB, offset@CCCC */
     mov     r2, rINST, lsr #12          @ r2<- B
     GET_VREG(r3, r2)                    @ r3<- object we're operating on
@@ -7585,7 +7585,7 @@
 /* ------------------------------ */
     .balign 64
 .L_OP_IPUT_WIDE_QUICK: /* 0xf6 */
-/* File: armv4/OP_IPUT_WIDE_QUICK.S */
+/* File: armv4t/OP_IPUT_WIDE_QUICK.S */
     /* iput-wide-quick vA, vB, offset@CCCC */
     mov     r0, rINST, lsr #8           @ r0<- A(+)
     mov     r1, rINST, lsr #12          @ r1<- B
diff --git a/vm/mterp/out/InterpC-armv4.c b/vm/mterp/out/InterpC-armv4t.c
similarity index 99%
rename from vm/mterp/out/InterpC-armv4.c
rename to vm/mterp/out/InterpC-armv4t.c
index 2fcdcab..7f101a9 100644
--- a/vm/mterp/out/InterpC-armv4.c
+++ b/vm/mterp/out/InterpC-armv4t.c
@@ -1,5 +1,5 @@
 /*
- * This file was generated automatically by gen-mterp.py for 'armv4'.
+ * This file was generated automatically by gen-mterp.py for 'armv4t'.
  *
  * --> DO NOT EDIT <--
  */
diff --git a/vm/mterp/rebuild.sh b/vm/mterp/rebuild.sh
index d1c6983..1380f69 100755
--- a/vm/mterp/rebuild.sh
+++ b/vm/mterp/rebuild.sh
@@ -19,7 +19,7 @@
 # generated as part of the build.
 #
 set -e
-for arch in portstd portdbg allstubs armv4 armv5te x86; do TARGET_ARCH_EXT=$arch make -f Makefile-mterp; done
+for arch in portstd portdbg allstubs armv4t armv5te x86; do TARGET_ARCH_EXT=$arch make -f Makefile-mterp; done
 
 # These aren't actually used, so just go ahead and remove them.  The correct
 # approach is to prevent them from being generated in the first place, but
diff --git a/vm/native/dalvik_system_VMDebug.c b/vm/native/dalvik_system_VMDebug.c
index 9eccb76..ec6d92e 100644
--- a/vm/native/dalvik_system_VMDebug.c
+++ b/vm/native/dalvik_system_VMDebug.c
@@ -244,6 +244,23 @@
 }
 
 /*
+ * static boolean isMethodTracingActive()
+ *
+ * Determine whether method tracing is currently active.
+ */
+static void Dalvik_dalvik_system_VMDebug_isMethodTracingActive(const u4* args,
+    JValue* pResult)
+{
+    UNUSED_PARAMETER(args);
+
+#ifdef WITH_PROFILER
+    RETURN_BOOLEAN(dvmIsMethodTraceActive());
+#else
+    RETURN_BOOLEAN(false);
+#endif
+}
+
+/*
  * static void stopMethodTracing()
  *
  * Stop method tracing.
@@ -527,6 +544,7 @@
 #ifdef WITH_HPROF
     StringObject* fileNameStr = (StringObject*) args[0];
     char* fileName;
+    int result;
 
     if (fileNameStr == NULL) {
         dvmThrowException("Ljava/lang/NullPointerException;", NULL);
@@ -540,8 +558,15 @@
         RETURN_VOID();
     }
 
-    hprofDumpHeap(fileName);
+    result = hprofDumpHeap(fileName);
     free(fileName);
+
+    if (result != 0) {
+        /* ideally we'd throw something more specific based on actual failure */
+        dvmThrowException("Ljava/lang/RuntimeException;",
+            "Failure during heap dump -- check log output for details");
+        RETURN_VOID();
+    }
 #else
     dvmThrowException("Ljava/lang/UnsupportedOperationException;", NULL);
 #endif
@@ -562,6 +587,8 @@
         Dalvik_dalvik_system_VMDebug_stopAllocCounting },
     { "startMethodTracing",         "(Ljava/lang/String;II)V",
         Dalvik_dalvik_system_VMDebug_startMethodTracing },
+    { "isMethodTracingActive",      "()Z",
+        Dalvik_dalvik_system_VMDebug_isMethodTracingActive },
     { "stopMethodTracing",          "()V",
         Dalvik_dalvik_system_VMDebug_stopMethodTracing },
     { "startEmulatorTracing",       "()V",
diff --git a/vm/native/java_lang_reflect_Constructor.c b/vm/native/java_lang_reflect_Constructor.c
index 82b72ee..6878f7b 100644
--- a/vm/native/java_lang_reflect_Constructor.c
+++ b/vm/native/java_lang_reflect_Constructor.c
@@ -39,6 +39,12 @@
 /*
  * public int constructNative(Object[] args, Class declaringClass,
  *     Class[] parameterTypes, int slot, boolean noAccessCheck)
+ *
+ * We get here through Constructor.newInstance().  The Constructor object
+ * would not be available if the constructor weren't public (per the
+ * definition of Class.getConstructor), so we can skip the method access
+ * check.  We can also safely assume the constructor isn't associated
+ * with an interface, array, or primitive class.
  */
 static void Dalvik_java_lang_reflect_Constructor_constructNative(
     const u4* args, JValue* pResult)
@@ -52,6 +58,22 @@
     Object* newObj;
     Method* meth;
 
+    if (dvmIsAbstractClass(declaringClass)) {
+        dvmThrowExceptionWithClassMessage("Ljava/lang/InstantiationException;",
+            declaringClass->descriptor);
+        RETURN_VOID();
+    }
+
+    /* initialize the class if it hasn't been already */
+    if (!dvmIsClassInitialized(declaringClass)) {
+        if (!dvmInitClass(declaringClass)) {
+            LOGW("Class init failed in Constructor.constructNative (%s)\n",
+                declaringClass->descriptor);
+            assert(dvmCheckException(dvmThreadSelf()));
+            RETURN_VOID();
+        }
+    }
+
     newObj = dvmAllocObject(declaringClass, ALLOC_DEFAULT);
     if (newObj == NULL)
         RETURN_PTR(NULL);
diff --git a/vm/oo/Class.c b/vm/oo/Class.c
index c7ab763..47e2a87 100644
--- a/vm/oo/Class.c
+++ b/vm/oo/Class.c
@@ -151,6 +151,9 @@
 may not be worth the performance hit.
 */
 
+#define INITIAL_CLASS_SERIAL_NUMBER 0x50000000
+#define ZYGOTE_CLASS_CUTOFF 2000
+
 static ClassPathEntry* processClassPath(const char* pathStr, bool isBootstrap);
 static void freeCpeArray(ClassPathEntry* cpe);
 
@@ -293,8 +296,15 @@
      * Class serial number.  We start with a high value to make it distinct
      * in binary dumps (e.g. hprof).
      */
-    gDvm.classSerialNumber = 0x50000000;
+    gDvm.classSerialNumber = INITIAL_CLASS_SERIAL_NUMBER;
 
+    /* Set up the table we'll use for tracking initiating loaders for
+     * early classes.
+     * If it's NULL, we just fall back to the InitiatingLoaderList in the
+     * ClassObject, so it's not fatal to fail this allocation.
+     */
+    gDvm.initiatingLoaderList =
+        calloc(ZYGOTE_CLASS_CUTOFF, sizeof(InitiatingLoaderList));
 
     /* This placeholder class is used while a ClassObject is
      * loading/linking so those not in the know can still say
@@ -346,6 +356,8 @@
     gDvm.bootClassPath = NULL;
 
     dvmLinearAllocDestroy(NULL);
+
+    free(gDvm.initiatingLoaderList);
 }
 
 
@@ -797,6 +809,18 @@
 
 #define kInitLoaderInc  4       /* must be power of 2 */
 
+static InitiatingLoaderList *dvmGetInitiatingLoaderList(ClassObject* clazz)
+{
+    assert(clazz->serialNumber > INITIAL_CLASS_SERIAL_NUMBER);
+    int classIndex = clazz->serialNumber-INITIAL_CLASS_SERIAL_NUMBER;
+    if (gDvm.initiatingLoaderList != NULL &&
+        classIndex < ZYGOTE_CLASS_CUTOFF) {
+        return &(gDvm.initiatingLoaderList[classIndex]);
+    } else {
+        return &(clazz->initiatingLoaderList);
+    }
+}
+
 /*
  * Determine if "loader" appears in clazz' initiating loader list.
  *
@@ -820,9 +844,13 @@
     /*
      * Scan the list for a match.  The list is expected to be short.
      */
+    /* Cast to remove the const from clazz, but use const loaderList */
+    ClassObject* nonConstClazz = (ClassObject*) clazz;
+    const InitiatingLoaderList *loaderList =
+        dvmGetInitiatingLoaderList(nonConstClazz);
     int i;
-    for (i = clazz->initiatingLoaderCount-1; i >= 0; --i) {
-        if (clazz->initiatingLoaders[i] == loader) {
+    for (i = loaderList->initiatingLoaderCount-1; i >= 0; --i) {
+        if (loaderList->initiatingLoaders[i] == loader) {
             //LOGI("+++ found initiating match %p in %s\n",
             //    loader, clazz->descriptor);
             return true;
@@ -854,10 +882,10 @@
          * pretty minor, and probably outweighs the O(n^2) hit for
          * checking before every add, so we may not want to do this.
          */
-        if (false && dvmLoaderInInitiatingList(clazz, loader)) {
-            LOGW("WOW: simultaneous add of initiating class loader\n");
-            goto bail_unlock;
-        }
+        //if (dvmLoaderInInitiatingList(clazz, loader)) {
+        //    LOGW("WOW: simultaneous add of initiating class loader\n");
+        //    goto bail_unlock;
+        //}
 
         /*
          * The list never shrinks, so we just keep a count of the
@@ -867,25 +895,26 @@
          * The pointer is initially NULL, so we *do* want to call realloc
          * when count==0.
          */
-        if ((clazz->initiatingLoaderCount & (kInitLoaderInc-1)) == 0) {
+        InitiatingLoaderList *loaderList = dvmGetInitiatingLoaderList(clazz);
+        if ((loaderList->initiatingLoaderCount & (kInitLoaderInc-1)) == 0) {
             Object** newList;
 
-            newList = (Object**) realloc(clazz->initiatingLoaders,
-                        (clazz->initiatingLoaderCount + kInitLoaderInc)
+            newList = (Object**) realloc(loaderList->initiatingLoaders,
+                        (loaderList->initiatingLoaderCount + kInitLoaderInc)
                          * sizeof(Object*));
             if (newList == NULL) {
                 /* this is mainly a cache, so it's not the EotW */
                 assert(false);
                 goto bail_unlock;
             }
-            clazz->initiatingLoaders = newList;
+            loaderList->initiatingLoaders = newList;
 
             //LOGI("Expanded init list to %d (%s)\n",
-            //    clazz->initiatingLoaderCount+kInitLoaderInc,
+            //    loaderList->initiatingLoaderCount+kInitLoaderInc,
             //    clazz->descriptor);
         }
-
-        clazz->initiatingLoaders[clazz->initiatingLoaderCount++] = loader;
+        loaderList->initiatingLoaders[loaderList->initiatingLoaderCount++] =
+            loader;
 
 bail_unlock:
         dvmHashTableUnlock(gDvm.loadedClasses);
@@ -1889,8 +1918,9 @@
         dvmLinearFree(clazz->classLoader, virtualMethods);
     }
 
-    clazz->initiatingLoaderCount = -1;
-    NULL_AND_FREE(clazz->initiatingLoaders);
+    InitiatingLoaderList *loaderList = dvmGetInitiatingLoaderList(clazz);
+    loaderList->initiatingLoaderCount = -1;
+    NULL_AND_FREE(loaderList->initiatingLoaders);
 
     clazz->interfaceCount = -1;
     NULL_AND_LINEAR_FREE(clazz->interfaces);
diff --git a/vm/oo/Object.h b/vm/oo/Object.h
index 7ef8dac..18fbb36 100644
--- a/vm/oo/Object.h
+++ b/vm/oo/Object.h
@@ -24,6 +24,7 @@
 
 /* fwd decl */
 struct DataObject;
+struct InitiatingLoaderList;
 struct ClassObject;
 struct StringObject;
 struct ArrayObject;
@@ -35,6 +36,7 @@
 struct Field;
 struct RegisterMap;
 typedef struct DataObject DataObject;
+typedef struct InitiatingLoaderList InitiatingLoaderList;
 typedef struct ClassObject ClassObject;
 typedef struct StringObject StringObject;
 typedef struct ArrayObject ArrayObject;
@@ -248,6 +250,18 @@
 };
 
 /*
+ * For classes created early and thus probably in the zygote, the
+ * InitiatingLoaderList is kept in gDvm. Later classes use the structure in
+ * Object Class. This helps keep zygote pages shared.
+ */
+struct InitiatingLoaderList {
+    /* a list of initiating loader Objects; grown and initialized on demand */
+    Object**  initiatingLoaders;
+    /* count of loaders in the above list */
+    int       initiatingLoaderCount;
+};
+
+/*
  * Class objects have many additional fields.  This is used for both
  * classes and interfaces, including synthesized classes (arrays and
  * primitive types).
@@ -318,8 +332,9 @@
     Object*         classLoader;
 
     /* initiating class loader list */
-    Object**        initiatingLoaders;
-    int             initiatingLoaderCount;
+    /* NOTE: for classes with low serialNumber, these are unused, and the
+       values are kept in a table in gDvm. */
+    InitiatingLoaderList initiatingLoaderList;
 
     /* array of interfaces this class implements directly */
     int             interfaceCount;