Merge "[JIT] Clear inCodeCacheFlag on extended singlestep" into dalvik-dev
diff --git a/tests/090-loop-formation/expected.txt b/tests/090-loop-formation/expected.txt
new file mode 100644
index 0000000..b7e0bb3
--- /dev/null
+++ b/tests/090-loop-formation/expected.txt
@@ -0,0 +1,5 @@
+counter1 is 0
+counter2 is 32767
+counter3 is 32767
+counter4 is 0
+counter5 is 65534
diff --git a/tests/090-loop-formation/info.txt b/tests/090-loop-formation/info.txt
new file mode 100644
index 0000000..98d1d4b
--- /dev/null
+++ b/tests/090-loop-formation/info.txt
@@ -0,0 +1,3 @@
+Test loop formation heuristics and code generation. Basically the problem to
+catch here is to make sure that some never-exercised code blocks are included
+in the loop region, and the JIT compiler won't choke on unresolved fields.
diff --git a/tests/090-loop-formation/src/Main.java b/tests/090-loop-formation/src/Main.java
new file mode 100644
index 0000000..7c16667
--- /dev/null
+++ b/tests/090-loop-formation/src/Main.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+/*
+ * Create two versions of loops where the unresolved field is on either the
+ * taken or the non-taken path to make sure that the loop detection code bails
+ * on unresolved fields.
+ */
+public class Main {
+    static int counter1;
+    static int counter2;
+    static int counter3;
+    static int counter4;
+    static int counter5;
+
+    public static void main(String[] args) {
+        /* counter1 is not resolved */
+        for (int i = 0; i < 32767; i++) {
+            if (i < 0) {
+                counter1++;
+            } else {
+                counter2++;
+            }
+            counter5++;
+        }
+
+        /* counter4 is not resolved */
+        for (int i = 0; i < 32767; i++) {
+            if (i >= 0) {
+                counter3++;
+            } else {
+                counter4++;
+            }
+            counter5++;
+        }
+
+        System.out.println("counter1 is " + counter1);
+        System.out.println("counter2 is " + counter2);
+        System.out.println("counter3 is " + counter3);
+        System.out.println("counter4 is " + counter4);
+        System.out.println("counter5 is " + counter5);
+    }
+}
diff --git a/vm/Dvm.mk b/vm/Dvm.mk
index c9b0e27..d655a3a 100644
--- a/vm/Dvm.mk
+++ b/vm/Dvm.mk
@@ -120,8 +120,6 @@
 	alloc/CardTable.c \
 	alloc/HeapBitmap.c.arm \
 	alloc/HeapDebug.c \
-	alloc/HeapTable.c \
-	alloc/HeapWorker.c \
 	alloc/Heap.c.arm \
 	alloc/DdmHeap.c \
 	alloc/Verify.c \
diff --git a/vm/Globals.h b/vm/Globals.h
index 1cb4526..faafcc6 100644
--- a/vm/Globals.h
+++ b/vm/Globals.h
@@ -367,11 +367,14 @@
     int         offJavaLangRefReference_queueNext;
     int         offJavaLangRefReference_pendingNext;
 
-    /* method pointers - java.lang.ref.Reference */
-    Method*     methJavaLangRefReference_enqueueInternal;
+    /* field offsets - java.lang.ref.FinalizerReference */
+    int offJavaLangRefFinalizerReference_zombie;
 
-    /* more method pointers - java.lang.ref.FinalizerReference */
-    Method*     methJavaLangRefFinalizerReferenceAdd;
+    /* method pointers - java.lang.ref.ReferenceQueue */
+    Method* methJavaLangRefReferenceQueueAdd;
+
+    /* method pointers - java.lang.ref.FinalizerReference */
+    Method* methJavaLangRefFinalizerReferenceAdd;
 
     /* constructor method pointers; no vtable involved, so use Method* */
     Method*     methJavaLangStackTraceElement_init;
@@ -581,19 +584,6 @@
      */
     LinearAllocHdr* pBootLoaderAlloc;
 
-
-    /*
-     * Heap worker thread.
-     */
-    bool            heapWorkerInitialized;
-    bool            heapWorkerReady;
-    bool            haltHeapWorker;
-    pthread_t       heapWorkerHandle;
-    pthread_mutex_t heapWorkerLock;
-    pthread_cond_t  heapWorkerCond;
-    pthread_cond_t  heapWorkerIdleCond;
-    pthread_mutex_t heapWorkerListLock;
-
     /*
      * Compute some stats on loaded classes.
      */
diff --git a/vm/Init.c b/vm/Init.c
index f1afa85..a8cf258 100644
--- a/vm/Init.c
+++ b/vm/Init.c
@@ -1314,6 +1314,9 @@
     if (!dvmDebuggerStartup())
         goto fail;
 
+    if (!dvmGcStartupClasses())
+        goto fail;
+
     /*
      * Init for either zygote mode or non-zygote mode.  The key difference
      * is that we don't start any additional threads in Zygote mode.
diff --git a/vm/InitRefs.c b/vm/InitRefs.c
index b5b7526..5a9ba2a 100644
--- a/vm/InitRefs.c
+++ b/vm/InitRefs.c
@@ -320,6 +320,11 @@
         { NULL, NULL, NULL }
     };
 
+    static struct FieldInfo infoFinalizerReference[] = {
+        { &gDvm.offJavaLangRefFinalizerReference_zombie, "zombie", "Ljava/lang/Object;" },
+        { NULL, NULL, NULL }
+    };
+
     static struct FieldInfo infoConstructor[] = {
         { &gDvm.offJavaLangReflectConstructor_slot,      "slot",           "I" },
         { &gDvm.offJavaLangReflectConstructor_declClass, "declaringClass", "Ljava/lang/Class;" },
@@ -357,6 +362,7 @@
         { "Ljava/lang/ThreadGroup;",                infoThreadGroup },
         { "Ljava/lang/Throwable;",                  infoThrowable },
         { "Ljava/lang/VMThread;",                   infoVMThread },
+        { "Ljava/lang/ref/FinalizerReference;", infoFinalizerReference },
         { "Ljava/lang/reflect/Constructor;",        infoConstructor },
         { "Ljava/lang/reflect/Field;",              infoField },
         { "Ljava/lang/reflect/Method;",             infoMethod },
@@ -468,6 +474,8 @@
           "Lorg/apache/harmony/dalvik/ddmc/DdmServer;", "dispatch", "(I[BII)Lorg/apache/harmony/dalvik/ddmc/Chunk;" },
         { &gDvm.methDalvikDdmcServer_broadcast,
           "Lorg/apache/harmony/dalvik/ddmc/DdmServer;", "broadcast", "(I)V" },
+        { &gDvm.methJavaLangRefReferenceQueueAdd,
+          "Ljava/lang/ref/ReferenceQueue;", "add", "(Ljava/lang/ref/Reference;)V" },
         { NULL, NULL, NULL, NULL }
     };
 
@@ -587,26 +595,16 @@
 
 /* (documented in header) */
 bool dvmFindReferenceMembers(ClassObject* classReference) {
-    if (gDvm.methJavaLangRefReference_enqueueInternal != NULL) {
-        LOGE("Attempt to set up class Reference more than once\n");
-        return false;
-    }
-
     if (strcmp(classReference->descriptor, "Ljava/lang/ref/Reference;") != 0) {
         LOGE("Attempt to set up the wrong class as Reference\n");
         return false;
     }
-
-    /* Note: enqueueInternal() is private and thus a direct method. */
-
     return initFieldOffset(classReference, &gDvm.offJavaLangRefReference_pendingNext,
-                "pendingNext", "Ljava/lang/Object;")
+                "pendingNext", "Ljava/lang/ref/Reference;")
         && initFieldOffset(classReference, &gDvm.offJavaLangRefReference_queue,
                 "queue", "Ljava/lang/ref/ReferenceQueue;")
         && initFieldOffset(classReference, &gDvm.offJavaLangRefReference_queueNext,
                 "queueNext", "Ljava/lang/ref/Reference;")
         && initFieldOffset(classReference, &gDvm.offJavaLangRefReference_referent,
-                "referent", "Ljava/lang/Object;")
-        && initDirectMethodReferenceByClass(&gDvm.methJavaLangRefReference_enqueueInternal,
-                classReference, "enqueueInternal", "()Z");
+                "referent", "Ljava/lang/Object;");
 }
diff --git a/vm/Thread.c b/vm/Thread.c
index cdf49bc..087c2e0 100644
--- a/vm/Thread.c
+++ b/vm/Thread.c
@@ -3467,13 +3467,11 @@
 
 #ifdef HAVE_ANDROID_OS
     dvmPrintDebugMessage(target,
-        "(mutexes: tll=%x tsl=%x tscl=%x ghl=%x hwl=%x hwll=%x)\n",
+        "(mutexes: tll=%x tsl=%x tscl=%x ghl=%x)\n",
         gDvm.threadListLock.value,
         gDvm._threadSuspendLock.value,
         gDvm.threadSuspendCountLock.value,
-        gDvm.gcHeapLock.value,
-        gDvm.heapWorkerLock.value,
-        gDvm.heapWorkerListLock.value);
+        gDvm.gcHeapLock.value);
 #endif
 
     if (grabLock)
diff --git a/vm/alloc/Alloc.c b/vm/alloc/Alloc.c
index 6286f8d..33f45e8 100644
--- a/vm/alloc/Alloc.c
+++ b/vm/alloc/Alloc.c
@@ -20,7 +20,6 @@
 #include "alloc/Heap.h"
 #include "alloc/HeapInternal.h"
 #include "alloc/HeapSource.h"
-#include "alloc/HeapWorker.h"
 
 /*
  * Initialize the GC universe.
@@ -41,9 +40,6 @@
  */
 bool dvmGcStartupAfterZygote(void)
 {
-    if (!dvmHeapWorkerStartup()) {
-        return false;
-    }
     return dvmHeapStartupAfterZygote();
 }
 
@@ -52,7 +48,6 @@
  */
 void dvmGcThreadShutdown(void)
 {
-    dvmHeapWorkerShutdown();
     dvmHeapThreadShutdown();
 }
 
@@ -73,6 +68,44 @@
     return dvmHeapSourceStartupBeforeFork();
 }
 
+bool dvmGcStartupClasses(void)
+{
+    {
+        const char *klassName = "Ljava/lang/ref/ReferenceQueueThread;";
+        ClassObject *klass = dvmFindSystemClass(klassName);
+        if (klass == NULL) {
+            return false;
+        }
+        const char *methodName = "startReferenceQueue";
+        Method *method = dvmFindDirectMethodByDescriptor(klass, methodName, "()V");
+        if (method == NULL) {
+            return false;
+        }
+        Thread *self = dvmThreadSelf();
+        assert(self != NULL);
+        JValue unusedResult;
+        dvmCallMethod(self, method, NULL, &unusedResult);
+    }
+    {
+        const char *klassName = "Ljava/lang/FinalizerThread;";
+        ClassObject *klass = dvmFindSystemClass(klassName);
+        if (klass == NULL) {
+            return false;
+        }
+        const char *methodName = "startFinalizer";
+        Method *method = dvmFindDirectMethodByDescriptor(klass, methodName, "()V");
+        if (method == NULL) {
+            return false;
+        }
+        Thread *self = dvmThreadSelf();
+        assert(self != NULL);
+        JValue unusedResult;
+        dvmCallMethod(self, method, NULL, &unusedResult);
+    }
+
+    return true;
+}
+
 /*
  * Create a "stock instance" of an exception class.
  */
diff --git a/vm/alloc/Alloc.h b/vm/alloc/Alloc.h
index 2dc2ae6..aeba3f5 100644
--- a/vm/alloc/Alloc.h
+++ b/vm/alloc/Alloc.h
@@ -29,6 +29,7 @@
 bool dvmGcStartupAfterZygote(void);
 void dvmGcShutdown(void);
 void dvmGcThreadShutdown(void);
+bool dvmGcStartupClasses(void);
 
 /*
  * Do any last-minute preparation before we call fork() for the first time.
diff --git a/vm/alloc/Heap.c b/vm/alloc/Heap.c
index 5d88bc3..f38eb12 100644
--- a/vm/alloc/Heap.c
+++ b/vm/alloc/Heap.c
@@ -19,12 +19,10 @@
 #include "Dalvik.h"
 #include "alloc/HeapBitmap.h"
 #include "alloc/Verify.h"
-#include "alloc/HeapTable.h"
 #include "alloc/Heap.h"
 #include "alloc/HeapInternal.h"
 #include "alloc/DdmHeap.h"
 #include "alloc/HeapSource.h"
-#include "alloc/HeapWorker.h"
 #include "alloc/MarkSweep.h"
 
 #include "utils/threads.h"      // need Android thread priorities
@@ -91,9 +89,6 @@
     if (gcHeap == NULL) {
         return false;
     }
-    gcHeap->heapWorkerCurrentObject = NULL;
-    gcHeap->heapWorkerCurrentMethod = NULL;
-    gcHeap->heapWorkerInterpStartTime = 0LL;
     gcHeap->ddmHpifWhen = 0;
     gcHeap->ddmHpsgWhen = 0;
     gcHeap->ddmHpsgWhat = 0;
@@ -101,22 +96,15 @@
     gcHeap->ddmNhsgWhat = 0;
     gDvm.gcHeap = gcHeap;
 
-    /* Set up the lists and lock we'll use for finalizable
-     * and reference objects.
+    /* Set up the lists we'll use for cleared reference objects.
      */
-    dvmInitMutex(&gDvm.heapWorkerListLock);
-    gcHeap->referenceOperations = NULL;
+    gcHeap->clearedReferences = NULL;
 
     if (!dvmCardTableStartup(gDvm.heapMaximumSize)) {
         LOGE_HEAP("card table startup failed.");
         return false;
     }
 
-    /* Initialize the HeapWorker locks and other state
-     * that the GC uses.
-     */
-    dvmInitializeHeapWorkerState();
-
     return true;
 }
 
@@ -130,13 +118,6 @@
 //TODO: make sure we're locked
     if (gDvm.gcHeap != NULL) {
         dvmCardTableShutdown();
-         /* Tables are allocated on the native heap; they need to be
-         * cleaned up explicitly.  The process may stick around, so we
-         * don't want to leak any native memory.
-         */
-        dvmHeapFreeLargeTable(gDvm.gcHeap->referenceOperations);
-        gDvm.gcHeap->referenceOperations = NULL;
-
         /* Destroy the heap.  Any outstanding pointers will point to
          * unmapped memory (unless/until someone else maps it).  This
          * frees gDvm.gcHeap as a side-effect.
@@ -177,33 +158,6 @@
     dvmUnlockMutex(&gDvm.gcHeapLock);
 }
 
-/* Pop an object from the list of pending finalizations and
- * reference clears/enqueues, and return the object.
- * The caller must call dvmReleaseTrackedAlloc()
- * on the object when finished.
- *
- * Typically only called by the heap worker thread.
- */
-Object *dvmGetNextHeapWorkerObject()
-{
-    Object *obj;
-    GcHeap *gcHeap = gDvm.gcHeap;
-
-    dvmLockMutex(&gDvm.heapWorkerListLock);
-
-    obj = dvmHeapGetNextObjectFromLargeTable(&gcHeap->referenceOperations);
-    if (obj != NULL) {
-        /* Don't let the GC collect the object until the
-         * worker thread is done with it.
-         */
-        dvmAddTrackedAlloc(obj, NULL);
-    }
-
-    dvmUnlockMutex(&gDvm.heapWorkerListLock);
-
-    return obj;
-}
-
 /* Do a full garbage collection, which may grow the
  * heap as a side-effect if the live set is large.
  */
@@ -577,13 +531,6 @@
 
     gcHeap->gcRunning = true;
 
-    /*
-     * Grab the heapWorkerLock to prevent the HeapWorker thread from
-     * doing work.  If it's executing a finalizer or an enqueue operation
-     * it won't be holding the lock, so this should return quickly.
-     */
-    dvmLockMutex(&gDvm.heapWorkerLock);
-
     rootSuspend = dvmGetRelativeTimeMsec();
     dvmSuspendAllThreads(SUSPEND_FOR_GC);
     rootStart = dvmGetRelativeTimeMsec();
@@ -596,21 +543,6 @@
     if (!spec->isConcurrent) {
         oldThreadPriority = raiseThreadPriority();
     }
-
-    /* Make sure that the HeapWorker thread hasn't become
-     * wedged inside interp code.  If it has, this call will
-     * print a message and abort the VM.
-     */
-    dvmAssertHeapWorkerThreadRunning();
-
-    /* Lock the pendingFinalizationRefs list.
-     *
-     * Acquire the lock after suspending so the finalizer
-     * thread can't block in the RUNNING state while
-     * we try to suspend.
-     */
-    dvmLockMutex(&gDvm.heapWorkerListLock);
-
     if (gDvm.preVerify) {
         LOGV_HEAP("Verifying roots and heap before GC");
         verifyRootsAndHeap();
@@ -634,9 +566,11 @@
     /* dvmHeapScanMarkedObjects() will build the lists of known
      * instances of the Reference classes.
      */
-    gcHeap->softReferences = NULL;
-    gcHeap->weakReferences = NULL;
-    gcHeap->phantomReferences = NULL;
+    assert(gcHeap->softReferences == NULL);
+    assert(gcHeap->weakReferences == NULL);
+    assert(gcHeap->finalizerReferences == NULL);
+    assert(gcHeap->phantomReferences == NULL);
+    assert(gcHeap->clearedReferences == NULL);
 
     if (spec->isConcurrent) {
         /*
@@ -747,25 +681,12 @@
     currAllocated = dvmHeapSourceGetValue(HS_BYTES_ALLOCATED, NULL, 0);
     currFootprint = dvmHeapSourceGetValue(HS_FOOTPRINT, NULL, 0);
 
-    /* Now that we've freed up the GC heap, return any large
-     * free chunks back to the system.  They'll get paged back
-     * in the next time they're used.  Don't do it immediately,
-     * though;  if the process is still allocating a bunch of
-     * memory, we'll be taking a ton of page faults that we don't
-     * necessarily need to.
-     *
-     * Cancel any old scheduled trims, and schedule a new one.
-     */
-    dvmScheduleHeapSourceTrim(5);  // in seconds
-
     dvmMethodTraceGCEnd();
     LOGV_HEAP("GC finished");
 
     gcHeap->gcRunning = false;
 
     LOGV_HEAP("Resuming threads");
-    dvmUnlockMutex(&gDvm.heapWorkerListLock);
-    dvmUnlockMutex(&gDvm.heapWorkerLock);
 
     if (spec->isConcurrent) {
         /*
@@ -787,6 +708,11 @@
         }
     }
 
+    /*
+     * Move queue of pending references back into Java.
+     */
+    dvmEnqueueClearedReferences(&gDvm.gcHeap->clearedReferences);
+
     percentFree = 100 - (size_t)(100.0f * (float)currAllocated / currFootprint);
     if (!spec->isConcurrent) {
         u4 markSweepTime = dirtyEnd - rootStart;
diff --git a/vm/alloc/HeapInternal.h b/vm/alloc/HeapInternal.h
index 7f8c9c5..1d1be07 100644
--- a/vm/alloc/HeapInternal.h
+++ b/vm/alloc/HeapInternal.h
@@ -19,9 +19,6 @@
 #ifndef _DALVIK_ALLOC_HEAP_INTERNAL
 #define _DALVIK_ALLOC_HEAP_INTERNAL
 
-#include <time.h>  // for struct timespec
-
-#include "HeapTable.h"
 #include "MarkSweep.h"
 
 typedef struct HeapSource HeapSource;
@@ -39,34 +36,9 @@
     Object *finalizerReferences;
     Object *phantomReferences;
 
-    /* The list of Reference objects that need to be cleared and/or
-     * enqueued.  The bottom two bits of the object pointers indicate
-     * whether they should be cleared and/or enqueued.
-     *
-     * This table is protected by gDvm.heapWorkerListLock, which must
-     * be acquired after the heap lock.
+    /* The list of Reference objects that need to be enqueued.
      */
-    LargeHeapRefTable  *referenceOperations;
-
-    /* If non-null, the method that the HeapWorker is currently
-     * executing.
-     */
-    Object *heapWorkerCurrentObject;
-    Method *heapWorkerCurrentMethod;
-
-    /* If heapWorkerCurrentObject is non-null, this gives the time when
-     * HeapWorker started executing that method.  The time value must come
-     * from dvmGetRelativeTimeUsec().
-     *
-     * The "Cpu" entry tracks the per-thread CPU timer (when available).
-     */
-    u8 heapWorkerInterpStartTime;
-    u8 heapWorkerInterpCpuStartTime;
-
-    /* If any fields are non-zero, indicates the next (absolute) time that
-     * the HeapWorker thread should call dvmHeapSourceTrim().
-     */
-    struct timespec heapWorkerNextTrim;
+    Object *clearedReferences;
 
     /* The current state of the mark step.
      * Only valid during a GC.
diff --git a/vm/alloc/HeapTable.c b/vm/alloc/HeapTable.c
deleted file mode 100644
index 6c9034a..0000000
--- a/vm/alloc/HeapTable.c
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * Copyright (C) 2008 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.
- */
-
-#include "Dalvik.h"
-#include "alloc/HeapTable.h"
-#include "alloc/HeapInternal.h"
-
-#include <limits.h> // for INT_MAX
-
-static const int kLargeHeapRefTableNElems = 1024;
-static const int  kFinalizableRefDefault = 128;
-
-bool dvmHeapInitHeapRefTable(ReferenceTable *refs)
-{
-    return dvmInitReferenceTable(refs, kFinalizableRefDefault, INT_MAX);
-}
-
-/*
- * Large, non-contiguous reference tables
- */
-
-bool dvmHeapAddRefToLargeTable(LargeHeapRefTable **tableP, Object *ref)
-{
-    LargeHeapRefTable *table;
-
-    assert(tableP != NULL);
-    assert(ref != NULL);
-
-    /* Make sure that a table with a free slot is
-     * at the head of the list.
-     */
-    if (*tableP != NULL) {
-        table = *tableP;
-        LargeHeapRefTable *prevTable;
-
-        /* Find an empty slot for this reference.
-         */
-        prevTable = NULL;
-        while (table != NULL && dvmIsReferenceTableFull(&table->refs)) {
-            prevTable = table;
-            table = table->next;
-        }
-        if (table != NULL) {
-            if (prevTable != NULL) {
-                /* Move the table to the head of the list.
-                 */
-                prevTable->next = table->next;
-                table->next = *tableP;
-                *tableP = table;
-            }
-            /* else it's already at the head. */
-
-            goto insert;
-        }
-        /* else all tables are already full;
-         * fall through to the alloc case.
-         */
-    }
-
-    /* Allocate a new table.
-     */
-    table = (LargeHeapRefTable *)calloc(1, sizeof(LargeHeapRefTable));
-    if (table == NULL) {
-        LOGE_HEAP("Can't allocate a new large ref table\n");
-        return false;
-    }
-    if (!dvmInitReferenceTable(&table->refs,
-                               kLargeHeapRefTableNElems,
-                               INT_MAX)) {
-        LOGE_HEAP("Can't initialize a new large ref table\n");
-        free(table);
-        return false;
-    }
-
-    /* Stick it at the head.
-     */
-    table->next = *tableP;
-    *tableP = table;
-
-insert:
-    /* Insert the reference.
-     */
-    assert(table == *tableP);
-    assert(table != NULL);
-    assert(!dvmIsReferenceTableFull(&table->refs));
-    *table->refs.nextEntry++ = ref;
-
-    return true;
-}
-
-bool dvmHeapAddTableToLargeTable(LargeHeapRefTable **tableP, ReferenceTable *refs)
-{
-    LargeHeapRefTable *table;
-
-    /* Allocate a node.
-     */
-    table = (LargeHeapRefTable *)calloc(1, sizeof(LargeHeapRefTable));
-    if (table == NULL) {
-        LOGE_HEAP("Can't allocate a new large ref table\n");
-        return false;
-    }
-    table->refs = *refs;
-
-    /* Insert the table into the list.
-     */
-    table->next = *tableP;
-    *tableP = table;
-
-    return true;
-}
-
-/* Frees everything associated with the LargeHeapRefTable.
- */
-void dvmHeapFreeLargeTable(LargeHeapRefTable *table)
-{
-    while (table != NULL) {
-        LargeHeapRefTable *next = table->next;
-        dvmClearReferenceTable(&table->refs);
-        free(table);
-        table = next;
-    }
-}
-
-Object *dvmHeapGetNextObjectFromLargeTable(LargeHeapRefTable **pTable)
-{
-    LargeHeapRefTable *table;
-    Object *obj;
-
-    assert(pTable != NULL);
-
-    obj = NULL;
-    table = *pTable;
-    if (table != NULL) {
-        ReferenceTable *refs = &table->refs;
-
-        /* We should never have an empty table node in the list.
-         */
-        assert(dvmReferenceTableEntries(refs) != 0);
-
-        /* Remove and return the last entry in the list.
-         */
-        obj = *--refs->nextEntry;
-
-        /* If this was the last entry in the table node,
-         * free it and patch up the list.
-         */
-        if (refs->nextEntry == refs->table) {
-            *pTable = table->next;
-            dvmClearReferenceTable(refs);
-            free(table);
-        }
-    }
-
-    return obj;
-}
diff --git a/vm/alloc/HeapTable.h b/vm/alloc/HeapTable.h
deleted file mode 100644
index 175111d..0000000
--- a/vm/alloc/HeapTable.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2008 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.
- */
-#ifndef _DALVIK_ALLOC_HEAP_TABLE
-#define _DALVIK_ALLOC_HEAP_TABLE
-
-#include "ReferenceTable.h"
-
-struct LargeHeapRefTable {
-    struct LargeHeapRefTable *next;
-    ReferenceTable refs;
-};
-
-typedef struct LargeHeapRefTable LargeHeapRefTable;
-
-bool dvmHeapInitHeapRefTable(ReferenceTable *refs);
-void dvmHeapFreeLargeTable(LargeHeapRefTable *table);
-bool dvmHeapAddRefToLargeTable(LargeHeapRefTable **tableP, Object *ref);
-void dvmHeapMarkLargeTableRefs(LargeHeapRefTable *table);
-bool dvmHeapAddTableToLargeTable(LargeHeapRefTable **tableP,
-        ReferenceTable *refs);
-Object *dvmHeapGetNextObjectFromLargeTable(LargeHeapRefTable **pTable);
-
-#endif  // _DALVIK_ALLOC_HEAP_TABLE
diff --git a/vm/alloc/HeapWorker.c b/vm/alloc/HeapWorker.c
deleted file mode 100644
index 6017381..0000000
--- a/vm/alloc/HeapWorker.c
+++ /dev/null
@@ -1,472 +0,0 @@
-/*
- * Copyright (C) 2008 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.
- */
-
-/*
- * An async worker thread to handle certain heap operations that need
- * to be done in a separate thread to avoid synchronization problems.
- * HeapWorkers and reference enqueuing are handled by this thread.
- * The VM does all clearing.
- */
-#include "Dalvik.h"
-#include "alloc/HeapInternal.h"
-#include "alloc/HeapWorker.h"
-
-#include <sys/time.h>
-#include <stdlib.h>
-#include <pthread.h>
-#include <signal.h>
-#include <errno.h>  // for ETIMEDOUT, etc.
-
-static void* heapWorkerThreadStart(void* arg);
-
-/*
- * Initialize any HeapWorker state that Heap.c
- * cares about.  This lets the GC start before the
- * HeapWorker thread is initialized.
- */
-void dvmInitializeHeapWorkerState()
-{
-    assert(!gDvm.heapWorkerInitialized);
-
-    dvmInitMutex(&gDvm.heapWorkerLock);
-    pthread_cond_init(&gDvm.heapWorkerCond, NULL);
-    pthread_cond_init(&gDvm.heapWorkerIdleCond, NULL);
-
-    gDvm.heapWorkerInitialized = true;
-}
-
-/*
- * Crank up the heap worker thread.
- *
- * Does not return until the thread is ready for business.
- */
-bool dvmHeapWorkerStartup(void)
-{
-    assert(!gDvm.haltHeapWorker);
-    assert(!gDvm.heapWorkerReady);
-    assert(gDvm.heapWorkerHandle == 0);
-    assert(gDvm.heapWorkerInitialized);
-
-    /* use heapWorkerLock/heapWorkerCond to communicate readiness */
-    dvmLockMutex(&gDvm.heapWorkerLock);
-
-//BUG: If a GC happens in here or in the new thread while we hold the lock,
-//     the GC will deadlock when trying to acquire heapWorkerLock.
-    if (!dvmCreateInternalThread(&gDvm.heapWorkerHandle,
-                "HeapWorker", heapWorkerThreadStart, NULL))
-    {
-        dvmUnlockMutex(&gDvm.heapWorkerLock);
-        return false;
-    }
-
-    /*
-     * Wait for the heap worker to come up.  We know the thread was created,
-     * so this should not get stuck.
-     */
-    while (!gDvm.heapWorkerReady) {
-        dvmWaitCond(&gDvm.heapWorkerCond, &gDvm.heapWorkerLock);
-    }
-
-    dvmUnlockMutex(&gDvm.heapWorkerLock);
-    return true;
-}
-
-/*
- * Shut down the heap worker thread if it was started.
- */
-void dvmHeapWorkerShutdown(void)
-{
-    void* threadReturn;
-
-    /* note: assuming that (pthread_t)0 is not a valid thread handle */
-    if (gDvm.heapWorkerHandle != 0) {
-        gDvm.haltHeapWorker = true;
-        dvmSignalHeapWorker(true);
-
-        /*
-         * We may not want to wait for the heapWorkers to complete.  It's
-         * a good idea to do so, in case they're holding some sort of OS
-         * resource that doesn't get reclaimed when the process exits
-         * (e.g. an open temp file).
-         */
-        if (pthread_join(gDvm.heapWorkerHandle, &threadReturn) != 0)
-            LOGW("HeapWorker thread join failed\n");
-        else if (gDvm.verboseShutdown)
-            LOGD("HeapWorker thread has shut down\n");
-
-        gDvm.heapWorkerReady = false;
-    }
-}
-
-/* Make sure that the HeapWorker thread hasn't spent an inordinate
- * amount of time inside a finalizer.
- *
- * Aborts the VM if the thread appears to be wedged.
- *
- * The caller must hold the heapWorkerLock to guarantee an atomic
- * read of the watchdog values.
- */
-void dvmAssertHeapWorkerThreadRunning()
-{
-    if (gDvm.gcHeap->heapWorkerCurrentObject != NULL) {
-        static const u8 HEAP_WORKER_WATCHDOG_TIMEOUT = 10*1000*1000LL; // 10sec
-
-        u8 heapWorkerInterpStartTime = gDvm.gcHeap->heapWorkerInterpStartTime;
-        u8 now = dvmGetRelativeTimeUsec();
-        u8 delta = now - heapWorkerInterpStartTime;
-
-        if (delta > HEAP_WORKER_WATCHDOG_TIMEOUT &&
-            (gDvm.debuggerActive || gDvm.nativeDebuggerActive))
-        {
-            /*
-             * Debugger suspension can block the thread indefinitely.  For
-             * best results we should reset this explicitly whenever the
-             * HeapWorker thread is resumed.  Unfortunately this is also
-             * affected by native debuggers, and we have no visibility
-             * into how they're manipulating us.  So, we ignore the
-             * watchdog and just reset the timer.
-             */
-            LOGI("Debugger is attached -- suppressing HeapWorker watchdog\n");
-            gDvm.gcHeap->heapWorkerInterpStartTime = now;   /* reset timer */
-        } else if (delta > HEAP_WORKER_WATCHDOG_TIMEOUT) {
-            /*
-             * Before we give up entirely, see if maybe we're just not
-             * getting any CPU time because we're stuck in a background
-             * process group.  If we successfully move the thread into the
-             * foreground we'll just leave it there (it doesn't do anything
-             * if the process isn't GCing).
-             */
-            dvmLockThreadList(NULL);
-            Thread* thread = dvmGetThreadByHandle(gDvm.heapWorkerHandle);
-            dvmUnlockThreadList();
-
-            if (thread != NULL) {
-                int priChangeFlags, threadPrio;
-                SchedPolicy threadPolicy;
-                priChangeFlags = dvmRaiseThreadPriorityIfNeeded(thread,
-                        &threadPrio, &threadPolicy);
-                if (priChangeFlags != 0) {
-                    LOGI("HeapWorker watchdog expired, raising priority"
-                         " and retrying\n");
-                    gDvm.gcHeap->heapWorkerInterpStartTime = now;
-                    return;
-                }
-            }
-
-            char* desc = dexProtoCopyMethodDescriptor(
-                    &gDvm.gcHeap->heapWorkerCurrentMethod->prototype);
-            LOGE("HeapWorker is wedged: %lldms spent inside %s.%s%s\n",
-                    delta / 1000,
-                    gDvm.gcHeap->heapWorkerCurrentObject->clazz->descriptor,
-                    gDvm.gcHeap->heapWorkerCurrentMethod->name, desc);
-            free(desc);
-            dvmDumpAllThreads(true);
-
-            /* try to get a debuggerd dump from the target thread */
-            dvmNukeThread(thread);
-
-            /* abort the VM */
-            dvmAbort();
-        } else if (delta > HEAP_WORKER_WATCHDOG_TIMEOUT / 2) {
-            char* desc = dexProtoCopyMethodDescriptor(
-                    &gDvm.gcHeap->heapWorkerCurrentMethod->prototype);
-            LOGW("HeapWorker may be wedged: %lldms spent inside %s.%s%s\n",
-                    delta / 1000,
-                    gDvm.gcHeap->heapWorkerCurrentObject->clazz->descriptor,
-                    gDvm.gcHeap->heapWorkerCurrentMethod->name, desc);
-            free(desc);
-        }
-    }
-}
-
-/*
- * Acquires a mutex, transitioning to the VMWAIT state if the mutex is
- * held.  This allows the thread to suspend while it waits for another
- * thread to release the mutex.
- */
-static void lockMutex(pthread_mutex_t *mu)
-{
-    Thread *self;
-    ThreadStatus oldStatus;
-
-    assert(mu != NULL);
-    if (dvmTryLockMutex(mu) != 0) {
-        self = dvmThreadSelf();
-        assert(self != NULL);
-        oldStatus = dvmChangeStatus(self, THREAD_VMWAIT);
-        dvmLockMutex(mu);
-        dvmChangeStatus(self, oldStatus);
-    }
-}
-
-static void callMethod(Thread *self, Object *obj, Method *method)
-{
-    JValue unused;
-
-    /* Keep track of the method we're about to call and
-     * the current time so that other threads can detect
-     * when this thread wedges and provide useful information.
-     */
-    gDvm.gcHeap->heapWorkerInterpStartTime = dvmGetRelativeTimeUsec();
-    gDvm.gcHeap->heapWorkerInterpCpuStartTime = dvmGetThreadCpuTimeUsec();
-    gDvm.gcHeap->heapWorkerCurrentMethod = method;
-    gDvm.gcHeap->heapWorkerCurrentObject = obj;
-
-    /* Call the method.
-     *
-     * Don't hold the lock when executing interpreted
-     * code.  It may suspend, and the GC needs to grab
-     * heapWorkerLock.
-     */
-    dvmUnlockMutex(&gDvm.heapWorkerLock);
-    if (false) {
-        /* Log entry/exit; this will likely flood the log enough to
-         * cause "logcat" to drop entries.
-         */
-        char tmpTag[16];
-        sprintf(tmpTag, "HW%d", self->systemTid);
-        LOG(LOG_DEBUG, tmpTag, "Call %s\n", method->clazz->descriptor);
-        dvmCallMethod(self, method, obj, &unused);
-        LOG(LOG_DEBUG, tmpTag, " done\n");
-    } else {
-        dvmCallMethod(self, method, obj, &unused);
-    }
-    /*
-     * Reacquire the heap worker lock in a suspend-friendly way.
-     */
-    lockMutex(&gDvm.heapWorkerLock);
-
-    gDvm.gcHeap->heapWorkerCurrentObject = NULL;
-    gDvm.gcHeap->heapWorkerCurrentMethod = NULL;
-    gDvm.gcHeap->heapWorkerInterpStartTime = 0LL;
-
-    /* Exceptions thrown during these calls interrupt
-     * the method, but are otherwise ignored.
-     */
-    if (dvmCheckException(self)) {
-#if DVM_SHOW_EXCEPTION >= 1
-        LOGI("Uncaught exception thrown by finalizer (will be discarded):\n");
-        dvmLogExceptionStackTrace();
-#endif
-        dvmClearException(self);
-    }
-}
-
-/* Process all enqueued heap work, including finalizers and reference
- * enqueueing. Clearing has already been done by the VM.
- *
- * Caller must hold gDvm.heapWorkerLock.
- */
-static void doHeapWork(Thread *self)
-{
-    Object *obj;
-    size_t numReferencesEnqueued;
-
-    assert(gDvm.methJavaLangRefReference_enqueueInternal != NULL);
-    numReferencesEnqueued = 0;
-    while ((obj = dvmGetNextHeapWorkerObject()) != NULL) {
-        /* Make sure the object hasn't been collected since
-         * being scheduled.
-         */
-        assert(dvmIsValidObject(obj));
-
-        /* Call the appropriate method(s).
-         */
-        assert(dvmGetFieldObject(
-                   obj, gDvm.offJavaLangRefReference_queue) != NULL);
-        assert(dvmGetFieldObject(
-                   obj, gDvm.offJavaLangRefReference_queueNext) == NULL);
-        numReferencesEnqueued++;
-        callMethod(self, obj, gDvm.methJavaLangRefReference_enqueueInternal);
-
-        /* Let the GC collect the object.
-         */
-        dvmReleaseTrackedAlloc(obj, self);
-    }
-    LOGV("Enqueued %zd references", numReferencesEnqueued);
-}
-
-/*
- * The heap worker thread sits quietly until the GC tells it there's work
- * to do.
- */
-static void* heapWorkerThreadStart(void* arg)
-{
-    Thread *self = dvmThreadSelf();
-
-    UNUSED_PARAMETER(arg);
-
-    LOGV("HeapWorker thread started (threadid=%d)\n", self->threadId);
-
-    /* tell the main thread that we're ready */
-    lockMutex(&gDvm.heapWorkerLock);
-    gDvm.heapWorkerReady = true;
-    dvmSignalCond(&gDvm.heapWorkerCond);
-    dvmUnlockMutex(&gDvm.heapWorkerLock);
-
-    lockMutex(&gDvm.heapWorkerLock);
-    while (!gDvm.haltHeapWorker) {
-        struct timespec trimtime;
-        bool timedwait = false;
-
-        /* We're done running interpreted code for now. */
-        dvmChangeStatus(NULL, THREAD_VMWAIT);
-
-        /* Signal anyone who wants to know when we're done. */
-        dvmBroadcastCond(&gDvm.heapWorkerIdleCond);
-
-        /* Trim the heap if we were asked to. */
-        trimtime = gDvm.gcHeap->heapWorkerNextTrim;
-        if (trimtime.tv_sec != 0 && trimtime.tv_nsec != 0) {
-            struct timespec now;
-
-#ifdef HAVE_TIMEDWAIT_MONOTONIC
-            clock_gettime(CLOCK_MONOTONIC, &now);       // relative time
-#else
-            struct timeval tvnow;
-            gettimeofday(&tvnow, NULL);                 // absolute time
-            now.tv_sec = tvnow.tv_sec;
-            now.tv_nsec = tvnow.tv_usec * 1000;
-#endif
-
-            if (trimtime.tv_sec < now.tv_sec ||
-                (trimtime.tv_sec == now.tv_sec &&
-                 trimtime.tv_nsec <= now.tv_nsec))
-            {
-                size_t madvisedSizes[HEAP_SOURCE_MAX_HEAP_COUNT];
-
-                /*
-                 * Acquire the gcHeapLock.  The requires releasing the
-                 * heapWorkerLock before the gcHeapLock is acquired.
-                 * It is possible that the gcHeapLock may be acquired
-                 * during a concurrent GC in which case heapWorkerLock
-                 * is held by the GC and we are unable to make forward
-                 * progress.  We avoid deadlock by releasing the
-                 * gcHeapLock and then waiting to be signaled when the
-                 * GC completes.  There is no guarantee that the next
-                 * time we are run will coincide with GC inactivity so
-                 * the check and wait must be performed within a loop.
-                 */
-                dvmUnlockMutex(&gDvm.heapWorkerLock);
-                dvmLockHeap();
-                dvmWaitForConcurrentGcToComplete();
-                dvmLockMutex(&gDvm.heapWorkerLock);
-
-                memset(madvisedSizes, 0, sizeof(madvisedSizes));
-                dvmHeapSourceTrim(madvisedSizes, HEAP_SOURCE_MAX_HEAP_COUNT);
-
-                dvmUnlockHeap();
-
-                trimtime.tv_sec = 0;
-                trimtime.tv_nsec = 0;
-                gDvm.gcHeap->heapWorkerNextTrim = trimtime;
-            } else {
-                timedwait = true;
-            }
-        }
-
-        /* sleep until signaled */
-        if (timedwait) {
-            int cc __attribute__ ((__unused__));
-#ifdef HAVE_TIMEDWAIT_MONOTONIC
-            cc = pthread_cond_timedwait_monotonic(&gDvm.heapWorkerCond,
-                    &gDvm.heapWorkerLock, &trimtime);
-#else
-            cc = pthread_cond_timedwait(&gDvm.heapWorkerCond,
-                    &gDvm.heapWorkerLock, &trimtime);
-#endif
-            assert(cc == 0 || cc == ETIMEDOUT);
-        } else {
-            dvmWaitCond(&gDvm.heapWorkerCond, &gDvm.heapWorkerLock);
-        }
-
-        /*
-         * Return to the running state before doing heap work.  This
-         * will block if the GC has initiated a suspend.  We release
-         * the heapWorkerLock beforehand for the GC to make progress
-         * and wait to be signaled after the GC completes.  There is
-         * no guarantee that the next time we are run will coincide
-         * with GC inactivity so the check and wait must be performed
-         * within a loop.
-         */
-        dvmUnlockMutex(&gDvm.heapWorkerLock);
-        dvmChangeStatus(NULL, THREAD_RUNNING);
-        dvmLockHeap();
-        dvmWaitForConcurrentGcToComplete();
-        dvmLockMutex(&gDvm.heapWorkerLock);
-        dvmUnlockHeap();
-        LOGV("HeapWorker is awake\n");
-
-        /* Process any events in the queue.
-         */
-        doHeapWork(self);
-    }
-    dvmUnlockMutex(&gDvm.heapWorkerLock);
-
-    if (gDvm.verboseShutdown)
-        LOGD("HeapWorker thread shutting down\n");
-    return NULL;
-}
-
-/*
- * Wake up the heap worker to let it know that there's work to be done.
- */
-void dvmSignalHeapWorker(bool shouldLock)
-{
-    if (shouldLock) {
-        dvmLockMutex(&gDvm.heapWorkerLock);
-    }
-
-    dvmSignalCond(&gDvm.heapWorkerCond);
-
-    if (shouldLock) {
-        dvmUnlockMutex(&gDvm.heapWorkerLock);
-    }
-}
-
-/*
- * Requests that dvmHeapSourceTrim() be called no sooner
- * than timeoutSec seconds from now.  If timeoutSec
- * is zero, any pending trim is cancelled.
- *
- * Caller must hold heapWorkerLock.
- */
-void dvmScheduleHeapSourceTrim(size_t timeoutSec)
-{
-    GcHeap *gcHeap = gDvm.gcHeap;
-    struct timespec timeout;
-
-    if (timeoutSec == 0) {
-        timeout.tv_sec = 0;
-        timeout.tv_nsec = 0;
-        /* Don't wake up the thread just to tell it to cancel.
-         * If it wakes up naturally, we can avoid the extra
-         * context switch.
-         */
-    } else {
-#ifdef HAVE_TIMEDWAIT_MONOTONIC
-        clock_gettime(CLOCK_MONOTONIC, &timeout);
-        timeout.tv_sec += timeoutSec;
-#else
-        struct timeval now;
-        gettimeofday(&now, NULL);
-        timeout.tv_sec = now.tv_sec + timeoutSec;
-        timeout.tv_nsec = now.tv_usec * 1000;
-#endif
-        dvmSignalHeapWorker(false);
-    }
-    gcHeap->heapWorkerNextTrim = timeout;
-}
diff --git a/vm/alloc/HeapWorker.h b/vm/alloc/HeapWorker.h
deleted file mode 100644
index 67babc3..0000000
--- a/vm/alloc/HeapWorker.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2008 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.
- */
-/*
- * Manage async heap tasks.
- */
-#ifndef _DALVIK_ALLOC_HEAP_WORKER
-#define _DALVIK_ALLOC_HEAP_WORKER
-
-/*
- * Initialize any HeapWorker state that Heap.c
- * cares about.  This lets the GC start before the
- * HeapWorker thread is initialized.
- */
-void dvmInitializeHeapWorkerState(void);
-
-/*
- * Initialization.  Starts/stops the worker thread.
- */
-bool dvmHeapWorkerStartup(void);
-void dvmHeapWorkerShutdown(void);
-
-/*
- * Tell the worker thread to wake up and do work.
- * If shouldLock is false, the caller must have already
- * acquired gDvm.heapWorkerLock.
- */
-void dvmSignalHeapWorker(bool shouldLock);
-
-/*
- * Requests that dvmHeapSourceTrim() be called no sooner
- * than timeoutSec seconds from now.  If timeoutSec
- * is zero, any pending trim is cancelled.
- *
- * Caller must hold heapWorkerLock.
- */
-void dvmScheduleHeapSourceTrim(size_t timeoutSec);
-
-/* Make sure that the HeapWorker thread hasn't spent an inordinate
- * amount of time inside interpreted code.
- *
- * Aborts the VM if the thread appears to be wedged.
- *
- * The caller must hold the heapWorkerLock.
- */
-void dvmAssertHeapWorkerThreadRunning();
-
-/*
- * Called by the worker thread to get the next object
- * to finalize/enqueue/clear.  Implemented in Heap.c.
- *
- * @param op The operation to perform on the returned object.
- *           Must be non-NULL.
- * @return The object to operate on, or NULL.
- */
-Object *dvmGetNextHeapWorkerObject();
-
-#endif /*_DALVIK_ALLOC_HEAP_WORKER*/
diff --git a/vm/alloc/MarkSweep.c b/vm/alloc/MarkSweep.c
index 69b75de..e26394c 100644
--- a/vm/alloc/MarkSweep.c
+++ b/vm/alloc/MarkSweep.c
@@ -20,7 +20,6 @@
 #include "alloc/HeapBitmapInlines.h"
 #include "alloc/HeapInternal.h"
 #include "alloc/HeapSource.h"
-#include "alloc/HeapWorker.h"
 #include "alloc/MarkSweep.h"
 #include "alloc/Visit.h"
 #include "alloc/VisitInlines.h"
@@ -342,8 +341,6 @@
  * - Primitive classes
  * - Special objects
  *   - gDvm.outOfMemoryObj
- * - Objects allocated with ALLOC_NO_GC
- * - Objects pending finalization (but not yet finalized)
  * - Objects in debugger object registry
  *
  * Don't need:
@@ -795,11 +792,7 @@
     assert(ref != NULL);
     assert(dvmGetFieldObject(ref, gDvm.offJavaLangRefReference_queue) != NULL);
     assert(dvmGetFieldObject(ref, gDvm.offJavaLangRefReference_queueNext) == NULL);
-    if (!dvmHeapAddRefToLargeTable(&gDvm.gcHeap->referenceOperations, ref)) {
-        LOGE_HEAP("enqueueReference(): no room for any more "
-                  "reference operations\n");
-        dvmAbort();
-    }
+    enqueuePendingReference(ref, &gDvm.gcHeap->clearedReferences);
 }
 
 /*
@@ -857,11 +850,9 @@
     GcMarkContext *ctx;
     Object *ref, *referent;
     size_t referentOffset;
-    bool doSignal;
 
     ctx = &gDvm.gcHeap->markContext;
     referentOffset = gDvm.offJavaLangRefReference_referent;
-    doSignal = false;
     while (*list != NULL) {
         ref = dequeuePendingReference(list);
         referent = dvmGetFieldObject(ref, referentOffset);
@@ -870,31 +861,23 @@
             clearReference(ref);
             if (isEnqueuable(ref)) {
                 enqueueReference(ref);
-                doSignal = true;
             }
         }
     }
-    /*
-     * If we cleared a reference with a reference queue we must notify
-     * the heap worker to append the reference.
-     */
-    if (doSignal) {
-        dvmSignalHeapWorker(false);
-    }
     assert(*list == NULL);
 }
 
 /*
  * Enqueues finalizer references with white referents.  White
- * referents are blackened, moved to the pendingNext field, and the
+ * referents are blackened, moved to the zombie field, and the
  * referent field is cleared.
  */
 static void enqueueFinalizerReferences(Object **list)
 {
     GcMarkContext *ctx = &gDvm.gcHeap->markContext;
     size_t referentOffset = gDvm.offJavaLangRefReference_referent;
-    size_t pendingNextOffset = gDvm.offJavaLangRefReference_pendingNext;
-    bool doSignal = false;
+    size_t zombieOffset = gDvm.offJavaLangRefFinalizerReference_zombie;
+    bool hasEnqueued = false;
     while (*list != NULL) {
         Object *ref = dequeuePendingReference(list);
         Object *referent = dvmGetFieldObject(ref, referentOffset);
@@ -902,15 +885,14 @@
             markObject(referent, ctx);
             /* If the referent is non-null the reference must queuable. */
             assert(isEnqueuable(ref));
-            dvmSetFieldObject(ref, pendingNextOffset, referent);
+            dvmSetFieldObject(ref, zombieOffset, referent);
             clearReference(ref);
             enqueueReference(ref);
-            doSignal = true;
+            hasEnqueued = true;
         }
     }
-    if (doSignal) {
+    if (hasEnqueued) {
         processMarkStack(ctx);
-        dvmSignalHeapWorker(false);
     }
     assert(*list == NULL);
 }
@@ -928,8 +910,8 @@
     assert(self != NULL);
     Method *meth = gDvm.methJavaLangRefFinalizerReferenceAdd;
     assert(meth != NULL);
-    JValue unused;
-    dvmCallMethod(self, meth, obj, &unused, obj);
+    JValue unusedResult;
+    dvmCallMethod(self, meth, NULL, &unusedResult, obj);
 }
 
 /*
@@ -982,6 +964,24 @@
     assert(*phantomReferences == NULL);
 }
 
+/*
+ * Pushes a list of cleared references out to the managed heap.
+ */
+void dvmEnqueueClearedReferences(Object **cleared)
+{
+    assert(cleared != NULL);
+    if (*cleared != NULL) {
+        Thread *self = dvmThreadSelf();
+        assert(self != NULL);
+        Method *meth = gDvm.methJavaLangRefReferenceQueueAdd;
+        assert(meth != NULL);
+        JValue unused;
+        Object *reference = *cleared;
+        dvmCallMethod(self, meth, NULL, &unused, reference);
+        *cleared = NULL;
+    }
+}
+
 void dvmHeapFinishMarkStep()
 {
     GcMarkContext *ctx;
diff --git a/vm/alloc/MarkSweep.h b/vm/alloc/MarkSweep.h
index c9f11e4..94bf3ad 100644
--- a/vm/alloc/MarkSweep.h
+++ b/vm/alloc/MarkSweep.h
@@ -59,5 +59,6 @@
 void dvmHeapSweepSystemWeaks(void);
 void dvmHeapSweepUnmarkedObjects(bool isPartial, bool isConcurrent,
                                  size_t *numObjects, size_t *numBytes);
+void dvmEnqueueClearedReferences(Object **references);
 
 #endif  // _DALVIK_ALLOC_MARK_SWEEP
diff --git a/vm/alloc/Visit.c b/vm/alloc/Visit.c
index 634611c..6ca1439 100644
--- a/vm/alloc/Visit.c
+++ b/vm/alloc/Visit.c
@@ -83,20 +83,6 @@
 }
 
 /*
- * Visits a large heap reference table.  These objects are list heads.
- * As such, it is valid for table to be NULL.
- */
-static void visitLargeHeapRefTable(RootVisitor *visitor,
-                                   LargeHeapRefTable *table,
-                                   RootType type, void *arg)
-{
-    assert(visitor != NULL);
-    for (; table != NULL; table = table->next) {
-        visitReferenceTable(visitor, &table->refs, 0, type, arg);
-    }
-}
-
-/*
  * Visits all stack slots except those belonging to native method
  * arguments.
  */
@@ -250,7 +236,6 @@
     dvmLockMutex(&gDvm.jniPinRefLock);
     visitReferenceTable(visitor, &gDvm.jniPinRefTable, 0, ROOT_VM_INTERNAL, arg);
     dvmUnlockMutex(&gDvm.jniPinRefLock);
-    visitLargeHeapRefTable(visitor, gDvm.gcHeap->referenceOperations, ROOT_REFERENCE_CLEANUP, arg);
     visitThreads(visitor, arg);
     (*visitor)(&gDvm.outOfMemoryObj, 0, ROOT_VM_INTERNAL, arg);
     (*visitor)(&gDvm.internalErrorObj, 0, ROOT_VM_INTERNAL, arg);
diff --git a/vm/alloc/Visit.h b/vm/alloc/Visit.h
index e7c52e5..a66839d 100644
--- a/vm/alloc/Visit.h
+++ b/vm/alloc/Visit.h
@@ -30,9 +30,7 @@
   ROOT_MONITOR_USED,
   ROOT_THREAD_OBJECT,
   ROOT_INTERNED_STRING,
-  ROOT_FINALIZING,
   ROOT_DEBUGGER,
-  ROOT_REFERENCE_CLEANUP,
   ROOT_VM_INTERNAL,
   ROOT_JNI_MONITOR,
 } RootType;
diff --git a/vm/compiler/Compiler.h b/vm/compiler/Compiler.h
index 12add75..35d34b3 100644
--- a/vm/compiler/Compiler.h
+++ b/vm/compiler/Compiler.h
@@ -209,6 +209,7 @@
 void dvmInitializeSSAConversion(struct CompilationUnit *cUnit);
 int dvmConvertSSARegToDalvik(const struct CompilationUnit *cUnit, int ssaReg);
 bool dvmCompilerLoopOpt(struct CompilationUnit *cUnit);
+void dvmCompilerInsertBackwardChaining(struct CompilationUnit *cUnit);
 void dvmCompilerNonLoopAnalysis(struct CompilationUnit *cUnit);
 bool dvmCompilerFindLocalLiveIn(struct CompilationUnit *cUnit,
                                 struct BasicBlock *bb);
@@ -239,4 +240,5 @@
 void *dvmCompilerGetInterpretTemplate();
 JitInstructionSetType dvmCompilerGetInterpretTemplateSet();
 u8 dvmGetRegResourceMask(int reg);
+void dvmDumpCFG(struct CompilationUnit *cUnit, const char *dirPrefix);
 #endif /* _DALVIK_VM_COMPILER */
diff --git a/vm/compiler/CompilerIR.h b/vm/compiler/CompilerIR.h
index 7b9987b..bdb69ce 100644
--- a/vm/compiler/CompilerIR.h
+++ b/vm/compiler/CompilerIR.h
@@ -54,11 +54,9 @@
     kChainingCellGap,
     /* Don't insert new fields between Gap and Last */
     kChainingCellLast = kChainingCellGap + 1,
-    kMethodEntryBlock,
-    kTraceEntryBlock,
+    kEntryBlock,
     kDalvikByteCode,
-    kTraceExitBlock,
-    kMethodExitBlock,
+    kExitBlock,
     kPCReconstruction,
     kExceptionHandling,
     kCatchEntry,
@@ -255,12 +253,13 @@
      */
     const u2 *switchOverflowPad;
 
-    /* New fields only for method-based compilation */
     JitMode jitMode;
     int numReachableBlocks;
     int numDalvikRegisters;             // method->registersSize + inlined
     BasicBlock *entryBlock;
     BasicBlock *exitBlock;
+    BasicBlock *puntBlock;              // punting to interp for exceptions
+    BasicBlock *backChainBlock;         // for loop-trace
     BasicBlock *curBlock;
     BasicBlock *nextCodegenBlock;       // for extended trace codegen
     GrowableList dfsOrder;
@@ -272,6 +271,7 @@
     BitVector *tempSSARegisterV;        // numSSARegs
     bool printSSANames;
     void *blockLabelList;
+    bool quitLoopMode;                  // cold path/complex bytecode
 } CompilationUnit;
 
 #if defined(WITH_SELF_VERIFICATION)
diff --git a/vm/compiler/Dataflow.c b/vm/compiler/Dataflow.c
index 26068a1..c3355e9 100644
--- a/vm/compiler/Dataflow.c
+++ b/vm/compiler/Dataflow.c
@@ -2190,8 +2190,7 @@
     GrowableList *ivList = cUnit->loopAnalysis->ivList;
     MIR *mir;
 
-    if (bb->blockType != kDalvikByteCode &&
-        bb->blockType != kTraceEntryBlock) {
+    if (bb->blockType != kDalvikByteCode && bb->blockType != kEntryBlock) {
         return false;
     }
 
@@ -2395,9 +2394,8 @@
         if (bb == NULL) break;
         if (bb->hidden == true) continue;
         if (bb->blockType == kDalvikByteCode ||
-            bb->blockType == kTraceEntryBlock ||
-            bb->blockType == kMethodEntryBlock ||
-            bb->blockType == kMethodExitBlock) {
+            bb->blockType == kEntryBlock ||
+            bb->blockType == kExitBlock) {
             bb->dataFlowInfo = (BasicBlockDataFlow *)
                 dvmCompilerNew(sizeof(BasicBlockDataFlow),
                                true);
diff --git a/vm/compiler/Frontend.c b/vm/compiler/Frontend.c
index 8272fb6..1338acc 100644
--- a/vm/compiler/Frontend.c
+++ b/vm/compiler/Frontend.c
@@ -566,6 +566,7 @@
     /* Handle the fallthrough path */
     bottomBlock->fallThrough = origBlock->fallThrough;
     origBlock->fallThrough = bottomBlock;
+    origBlock->needFallThroughBranch = true;
     dvmCompilerSetBit(bottomBlock->predecessors, origBlock->id);
     if (bottomBlock->fallThrough) {
         dvmCompilerClearBit(bottomBlock->fallThrough->predecessors,
@@ -633,7 +634,7 @@
 }
 
 /* Dump the CFG into a DOT graph */
-void dumpCFG(CompilationUnit *cUnit, const char *dirPrefix)
+void dvmDumpCFG(CompilationUnit *cUnit, const char *dirPrefix)
 {
     const Method *method = cUnit->method;
     FILE *file;
@@ -686,14 +687,16 @@
         BasicBlock *bb = (BasicBlock *) dvmGrowableListGetElement(blockList,
                                                                   blockIdx);
         if (bb == NULL) break;
-        if (bb->blockType == kMethodEntryBlock) {
+        if (bb->blockType == kEntryBlock) {
             fprintf(file, "  entry [shape=Mdiamond];\n");
-        } else if (bb->blockType == kMethodExitBlock) {
+        } else if (bb->blockType == kExitBlock) {
             fprintf(file, "  exit [shape=Mdiamond];\n");
         } else if (bb->blockType == kDalvikByteCode) {
             fprintf(file, "  block%04x [shape=record,label = \"{ \\\n",
                     bb->startOffset);
             const MIR *mir;
+            fprintf(file, "    {block id %d\\l}%s\\\n", bb->id,
+                    bb->firstMIRInsn ? " | " : " ");
             for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
                 fprintf(file, "    {%04x %s\\l}%s\\\n", mir->offset,
                         mir->ssaRep ?
@@ -834,7 +837,7 @@
             char blockName1[BLOCK_NAME_LEN], blockName2[BLOCK_NAME_LEN];
             dvmGetBlockName(bb, blockName1);
             dvmGetBlockName(predBB, blockName2);
-            dumpCFG(cUnit, "/sdcard/cfg/");
+            dvmDumpCFG(cUnit, "/sdcard/cfg/");
             LOGE("Successor %s not found from %s",
                  blockName1, blockName2);
             dvmAbort();
@@ -1186,8 +1189,8 @@
     cUnit.tryBlockAddr = tryBlockAddr;
 
     /* Create the default entry and exit blocks and enter them to the list */
-    BasicBlock *entryBlock = dvmCompilerNewBB(kMethodEntryBlock, numBlocks++);
-    BasicBlock *exitBlock = dvmCompilerNewBB(kMethodExitBlock, numBlocks++);
+    BasicBlock *entryBlock = dvmCompilerNewBB(kEntryBlock, numBlocks++);
+    BasicBlock *exitBlock = dvmCompilerNewBB(kExitBlock, numBlocks++);
 
     cUnit.entryBlock = entryBlock;
     cUnit.exitBlock = exitBlock;
@@ -1308,7 +1311,7 @@
     dvmCompilerMethodMIR2LIR(&cUnit);
 
     // Debugging only
-    //dumpCFG(&cUnit, "/sdcard/cfg/");
+    //dvmDumpCFG(&cUnit, "/sdcard/cfg/");
 
     /* Method is not empty */
     if (cUnit.firstLIRInsn) {
@@ -1348,8 +1351,8 @@
 
     curBlock->visited = true;
 
-    if (curBlock->blockType == kMethodEntryBlock ||
-        curBlock->blockType == kMethodExitBlock) {
+    if (curBlock->blockType == kEntryBlock ||
+        curBlock->blockType == kExitBlock) {
         return false;
     }
 
@@ -1397,6 +1400,34 @@
             break;
         }
         curOffset += width;
+        BasicBlock *nextBlock = findBlock(cUnit, curOffset,
+                                          /* split */
+                                          false,
+                                          /* create */
+                                          false);
+        if (nextBlock) {
+            /*
+             * The next instruction could be the target of a previously parsed
+             * forward branch so a block is already created. If the current
+             * instruction is not an unconditional branch, connect them through
+             * the fall-through link.
+             */
+            assert(curBlock->fallThrough == NULL ||
+                   curBlock->fallThrough == nextBlock ||
+                   curBlock->fallThrough == cUnit->exitBlock);
+
+            if ((curBlock->fallThrough == NULL) &&
+                (flags & kInstrCanContinue)) {
+                curBlock->needFallThroughBranch = true;
+                curBlock->fallThrough = nextBlock;
+                dvmCompilerSetBit(nextBlock->predecessors, curBlock->id);
+            }
+            /* Block has been visited - no more parsing needed */
+            if (nextBlock->visited == true) {
+                return true;
+            }
+            curBlock = nextBlock;
+        }
     }
     return true;
 }
@@ -1410,6 +1441,10 @@
     int numBlocks = 0;
     unsigned int curOffset = startOffset;
     bool changed;
+    BasicBlock *bb;
+#if defined(WITH_JIT_TUNING)
+    CompilerMethodStats *methodStats;
+#endif
 
     cUnit->jitMode = kJitLoop;
 
@@ -1420,9 +1455,9 @@
     dvmInitGrowableList(&cUnit->pcReconstructionList, 8);
 
     /* Create the default entry and exit blocks and enter them to the list */
-    BasicBlock *entryBlock = dvmCompilerNewBB(kMethodEntryBlock, numBlocks++);
+    BasicBlock *entryBlock = dvmCompilerNewBB(kEntryBlock, numBlocks++);
     entryBlock->startOffset = curOffset;
-    BasicBlock *exitBlock = dvmCompilerNewBB(kMethodExitBlock, numBlocks++);
+    BasicBlock *exitBlock = dvmCompilerNewBB(kExitBlock, numBlocks++);
 
     cUnit->entryBlock = entryBlock;
     cUnit->exitBlock = exitBlock;
@@ -1452,6 +1487,20 @@
         changed = exhaustTrace(cUnit, curBlock);
     } while (changed);
 
+    /* Backward chaining block */
+    bb = dvmCompilerNewBB(kChainingCellBackwardBranch, cUnit->numBlocks++);
+    dvmInsertGrowableList(&cUnit->blockList, (intptr_t) bb);
+    cUnit->backChainBlock = bb;
+
+    /* A special block to host PC reconstruction code */
+    bb = dvmCompilerNewBB(kPCReconstruction, cUnit->numBlocks++);
+    dvmInsertGrowableList(&cUnit->blockList, (intptr_t) bb);
+
+    /* And one final block that publishes the PC and raises the exception */
+    bb = dvmCompilerNewBB(kExceptionHandling, cUnit->numBlocks++);
+    dvmInsertGrowableList(&cUnit->blockList, (intptr_t) bb);
+    cUnit->puntBlock = bb;
+
     cUnit->numDalvikRegisters = cUnit->method->registersSize;
 
     /* Verify if all blocks are connected as claimed */
@@ -1465,15 +1514,75 @@
     if (!dvmCompilerBuildLoop(cUnit))
         goto bail;
 
+    dvmCompilerLoopOpt(cUnit);
+
+    /*
+     * Change the backward branch to the backward chaining cell after dataflow
+     * analsys/optimizations are done.
+     */
+    dvmCompilerInsertBackwardChaining(cUnit);
+
     dvmCompilerInitializeRegAlloc(cUnit);
 
     /* Allocate Registers using simple local allocation scheme */
     dvmCompilerLocalRegAlloc(cUnit);
 
-    if (gDvmJit.receivedSIGUSR2) {
-        dumpCFG(cUnit, "/sdcard/cfg/");
+    /* Convert MIR to LIR, etc. */
+    dvmCompilerMIR2LIR(cUnit);
+
+    /* Loop contains never executed blocks / heavy instructions */
+    if (cUnit->quitLoopMode) {
+        if (cUnit->printMe || gDvmJit.receivedSIGUSR2) {
+            LOGD("Loop trace @ offset %04x aborted due to unresolved code info",
+                 cUnit->entryBlock->startOffset);
+        }
+        goto bail;
     }
 
+    /* Convert LIR into machine code. Loop for recoverable retries */
+    do {
+        dvmCompilerAssembleLIR(cUnit, info);
+        cUnit->assemblerRetries++;
+        if (cUnit->printMe && cUnit->assemblerStatus != kSuccess)
+            LOGD("Assembler abort #%d on %d", cUnit->assemblerRetries,
+                  cUnit->assemblerStatus);
+    } while (cUnit->assemblerStatus == kRetryAll);
+
+    /* Loop is too big - bail out */
+    if (cUnit->assemblerStatus == kRetryHalve) {
+        goto bail;
+    }
+
+    if (cUnit->printMe || gDvmJit.receivedSIGUSR2) {
+        LOGD("Loop trace @ offset %04x", cUnit->entryBlock->startOffset);
+        dvmCompilerCodegenDump(cUnit);
+    }
+
+    /*
+     * If this trace uses class objects as constants,
+     * dvmJitInstallClassObjectPointers will switch the thread state
+     * to running and look up the class pointers using the descriptor/loader
+     * tuple stored in the callsite info structure. We need to make this window
+     * as short as possible since it is blocking GC.
+     */
+    if (cUnit->hasClassLiterals && info->codeAddress) {
+        dvmJitInstallClassObjectPointers(cUnit, (char *) info->codeAddress);
+    }
+
+    /*
+     * Since callsiteinfo is allocated from the arena, delay the reset until
+     * class pointers are resolved.
+     */
+    dvmCompilerArenaReset();
+
+    assert(cUnit->assemblerStatus == kSuccess);
+#if defined(WITH_JIT_TUNING)
+    /* Locate the entry to store compilation statistics for this method */
+    methodStats = dvmCompilerAnalyzeMethodBody(desc->method, false);
+    methodStats->nativeSize += cUnit->totalSize;
+#endif
+    return info->codeAddress != NULL;
+
 bail:
     /* Retry the original trace with JIT_OPT_NO_LOOP disabled */
     dvmCompilerArenaReset();
@@ -1539,6 +1648,10 @@
     /* Setup the method */
     cUnit.method = desc->method;
 
+    /* Store the trace descriptor and set the initial mode */
+    cUnit.traceDesc = desc;
+    cUnit.jitMode = kJitTrace;
+
     /* Initialize the PC reconstruction list */
     dvmInitGrowableList(&cUnit.pcReconstructionList, 8);
 
@@ -1620,7 +1733,7 @@
     }
 
     /* Allocate the entry block */
-    curBB = dvmCompilerNewBB(kTraceEntryBlock, numBlocks++);
+    curBB = dvmCompilerNewBB(kEntryBlock, numBlocks++);
     dvmInsertGrowableList(blockList, (intptr_t) curBB);
     curBB->startOffset = curOffset;
 
@@ -1714,7 +1827,6 @@
     for (blockId = 0; blockId < blockList->numUsed; blockId++) {
         curBB = (BasicBlock *) dvmGrowableListGetElement(blockList, blockId);
         MIR *lastInsn = curBB->lastMIRInsn;
-        BasicBlock *backwardCell;
         /* Skip empty blocks */
         if (lastInsn == NULL) {
             continue;
@@ -1743,7 +1855,6 @@
             targetOffset < curOffset &&
             (optHints & JIT_OPT_NO_LOOP) == 0) {
             dvmCompilerArenaReset();
-            /* TODO - constructed loop is abandoned for now */
             return compileLoop(&cUnit, startOffset, desc, numMaxInsts,
                                info, bailPtr, optHints);
         }
@@ -1782,46 +1893,6 @@
         curBB->needFallThroughBranch =
             ((flags & (kInstrCanBranch | kInstrCanSwitch | kInstrCanReturn |
                        kInstrInvoke)) == 0);
-
-        /* Only form a loop if JIT_OPT_NO_LOOP is not set */
-        if (curBB->taken == NULL &&
-            curBB->fallThrough == NULL &&
-            flags == (kInstrCanBranch | kInstrCanContinue) &&
-            fallThroughOffset == entryCodeBB->startOffset &&
-            JIT_OPT_NO_LOOP != (optHints & JIT_OPT_NO_LOOP)) {
-            BasicBlock *loopBranch = curBB;
-            BasicBlock *exitBB;
-            BasicBlock *exitChainingCell;
-
-            if (cUnit.printMe) {
-                LOGD("Natural loop detected!");
-            }
-            exitBB = dvmCompilerNewBB(kTraceExitBlock, numBlocks++);
-            dvmInsertGrowableList(blockList, (intptr_t) exitBB);
-            exitBB->startOffset = targetOffset;
-            exitBB->needFallThroughBranch = true;
-
-            loopBranch->taken = exitBB;
-            dvmCompilerSetBit(exitBB->predecessors, loopBranch->id);
-            backwardCell =
-                dvmCompilerNewBB(kChainingCellBackwardBranch, numBlocks++);
-            dvmInsertGrowableList(blockList, (intptr_t) backwardCell);
-            backwardCell->startOffset = entryCodeBB->startOffset;
-            loopBranch->fallThrough = backwardCell;
-            dvmCompilerSetBit(backwardCell->predecessors, loopBranch->id);
-
-            /* Create the chaining cell as the fallthrough of the exit block */
-            exitChainingCell = dvmCompilerNewBB(kChainingCellNormal,
-                                                numBlocks++);
-            dvmInsertGrowableList(blockList, (intptr_t) exitChainingCell);
-            exitChainingCell->startOffset = targetOffset;
-
-            exitBB->fallThrough = exitChainingCell;
-            dvmCompilerSetBit(exitChainingCell->predecessors, exitBB->id);
-
-            cUnit.hasLoop = true;
-        }
-
         if (lastInsn->dalvikInsn.opcode == OP_PACKED_SWITCH ||
             lastInsn->dalvikInsn.opcode == OP_SPARSE_SWITCH) {
             int i;
@@ -1936,6 +2007,7 @@
     /* And one final block that publishes the PC and raise the exception */
     curBB = dvmCompilerNewBB(kExceptionHandling, numBlocks++);
     dvmInsertGrowableList(blockList, (intptr_t) curBB);
+    cUnit.puntBlock = curBB;
 
     if (cUnit.printMe) {
         char* signature =
@@ -1953,7 +2025,6 @@
         free(signature);
     }
 
-    cUnit.traceDesc = desc;
     cUnit.numBlocks = numBlocks;
 
     /* Set the instruction set to use (NOTE: later components may change it) */
@@ -1969,26 +2040,7 @@
     /* Preparation for SSA conversion */
     dvmInitializeSSAConversion(&cUnit);
 
-    if (cUnit.hasLoop) {
-        /*
-         * Loop is not optimizable (for example lack of a single induction
-         * variable), punt and recompile the trace with loop optimization
-         * disabled.
-         */
-        bool loopOpt = dvmCompilerLoopOpt(&cUnit);
-        if (loopOpt == false) {
-            if (cUnit.printMe) {
-                LOGD("Loop is not optimizable - retry codegen");
-            }
-            /* Reset the compiler resource pool */
-            dvmCompilerArenaReset();
-            return dvmCompileTrace(desc, cUnit.numInsts, info, bailPtr,
-                                   optHints | JIT_OPT_NO_LOOP);
-        }
-    }
-    else {
-        dvmCompilerNonLoopAnalysis(&cUnit);
-    }
+    dvmCompilerNonLoopAnalysis(&cUnit);
 
     dvmCompilerInitializeRegAlloc(&cUnit);  // Needs to happen after SSA naming
 
diff --git a/vm/compiler/Loop.c b/vm/compiler/Loop.c
index b9ad3d3..ba8714c 100644
--- a/vm/compiler/Loop.c
+++ b/vm/compiler/Loop.c
@@ -21,89 +21,16 @@
 
 #define DEBUG_LOOP(X)
 
-/*
- * Given the current simple natural loops, the phi node placement can be
- * determined in the following fashion:
- *                    entry (B0)
- *              +---v   v
- *              |  loop body (B1)
- *              |       v
- *              |  loop back (B2)
- *              +---+   v
- *                     exit (B3)
- *
- *  1) Add live-ins of B1 to B0 as defs
- *  2) The intersect of defs(B0)/defs(B1) and defs(B2)/def(B0) are the variables
- *     that need PHI nodes in B1.
- */
-static void handlePhiPlacement(CompilationUnit *cUnit)
-{
-    BasicBlock *entry =
-        (BasicBlock *) dvmGrowableListGetElement(&cUnit->blockList, 0);
-    BasicBlock *loopBody =
-        (BasicBlock *) dvmGrowableListGetElement(&cUnit->blockList, 1);
-    BasicBlock *loopBranch =
-        (BasicBlock *) dvmGrowableListGetElement(&cUnit->blockList, 2);
-    dvmCopyBitVector(entry->dataFlowInfo->defV,
-                     loopBody->dataFlowInfo->liveInV);
-
-    BitVector *phiV = dvmCompilerAllocBitVector(cUnit->method->registersSize,
-                                                false);
-    BitVector *phi2V = dvmCompilerAllocBitVector(cUnit->method->registersSize,
-                                                 false);
-    dvmIntersectBitVectors(phiV, entry->dataFlowInfo->defV,
-                           loopBody->dataFlowInfo->defV);
-    dvmIntersectBitVectors(phi2V, entry->dataFlowInfo->defV,
-                           loopBranch->dataFlowInfo->defV);
-    dvmUnifyBitVectors(phiV, phiV, phi2V);
-
-    /* Insert the PHI MIRs */
-    int i;
-    for (i = 0; i < cUnit->method->registersSize; i++) {
-        if (!dvmIsBitSet(phiV, i)) {
-            continue;
-        }
-        MIR *phi = (MIR *)dvmCompilerNew(sizeof(MIR), true);
-        phi->dalvikInsn.opcode = kMirOpPhi;
-        phi->dalvikInsn.vA = i;
-        dvmCompilerPrependMIR(loopBody, phi);
-    }
-}
-
-static void fillPhiNodeContents(CompilationUnit *cUnit)
-{
-    BasicBlock *entry =
-        (BasicBlock *) dvmGrowableListGetElement(&cUnit->blockList, 0);
-    BasicBlock *loopBody =
-        (BasicBlock *) dvmGrowableListGetElement(&cUnit->blockList, 1);
-    BasicBlock *loopBranch =
-        (BasicBlock *) dvmGrowableListGetElement(&cUnit->blockList, 2);
-    MIR *mir;
-
-    for (mir = loopBody->firstMIRInsn; mir; mir = mir->next) {
-        if (mir->dalvikInsn.opcode != kMirOpPhi) break;
-        int dalvikReg = mir->dalvikInsn.vA;
-
-        mir->ssaRep->numUses = 2;
-        mir->ssaRep->uses = (int *)dvmCompilerNew(sizeof(int) * 2, false);
-        mir->ssaRep->uses[0] =
-            DECODE_REG(entry->dataFlowInfo->dalvikToSSAMap[dalvikReg]);
-        mir->ssaRep->uses[1] =
-            DECODE_REG(loopBranch->dataFlowInfo->dalvikToSSAMap[dalvikReg]);
-    }
-
-
-}
-
 #if 0
 /* Debugging routines */
 static void dumpConstants(CompilationUnit *cUnit)
 {
     int i;
+    LOGE("LOOP starting offset: %x", cUnit->entryBlock->startOffset);
     for (i = 0; i < cUnit->numSSARegs; i++) {
         if (dvmIsBitSet(cUnit->isConstantV, i)) {
             int subNReg = dvmConvertSSARegToDalvik(cUnit, i);
-            LOGE("s%d(v%d_%d) has %d", i,
+            LOGE("CONST: s%d(v%d_%d) has %d", i,
                  DECODE_REG(subNReg), DECODE_SUB(subNReg),
                  cUnit->constantValues[i]);
         }
@@ -114,24 +41,27 @@
 {
     unsigned int i;
     GrowableList *ivList = cUnit->loopAnalysis->ivList;
-    int *ssaToDalvikMap = (int *) cUnit->ssaToDalvikMap->elemList;
 
     for (i = 0; i < ivList->numUsed; i++) {
-        InductionVariableInfo *ivInfo = ivList->elemList[i];
+        InductionVariableInfo *ivInfo =
+            (InductionVariableInfo *) ivList->elemList[i];
+        int iv = dvmConvertSSARegToDalvik(cUnit, ivInfo->ssaReg);
         /* Basic IV */
         if (ivInfo->ssaReg == ivInfo->basicSSAReg) {
-            LOGE("BIV %d: s%d(v%d) + %d", i,
+            LOGE("BIV %d: s%d(v%d_%d) + %d", i,
                  ivInfo->ssaReg,
-                 ssaToDalvikMap[ivInfo->ssaReg] & 0xffff,
+                 DECODE_REG(iv), DECODE_SUB(iv),
                  ivInfo->inc);
         /* Dependent IV */
         } else {
-            LOGE("DIV %d: s%d(v%d) = %d * s%d(v%d) + %d", i,
+            int biv = dvmConvertSSARegToDalvik(cUnit, ivInfo->basicSSAReg);
+
+            LOGE("DIV %d: s%d(v%d_%d) = %d * s%d(v%d_%d) + %d", i,
                  ivInfo->ssaReg,
-                 ssaToDalvikMap[ivInfo->ssaReg] & 0xffff,
+                 DECODE_REG(iv), DECODE_SUB(iv),
                  ivInfo->m,
                  ivInfo->basicSSAReg,
-                 ssaToDalvikMap[ivInfo->basicSSAReg] & 0xffff,
+                 DECODE_REG(biv), DECODE_SUB(biv),
                  ivInfo->c);
         }
     }
@@ -162,6 +92,32 @@
 
 #endif
 
+static BasicBlock *findPredecessorBlock(const CompilationUnit *cUnit,
+                                        const BasicBlock *bb)
+{
+    int numPred = dvmCountSetBits(bb->predecessors);
+    BitVectorIterator bvIterator;
+    dvmBitVectorIteratorInit(bb->predecessors, &bvIterator);
+
+    if (numPred == 1) {
+        int predIdx = dvmBitVectorIteratorNext(&bvIterator);
+        return (BasicBlock *) dvmGrowableListGetElement(&cUnit->blockList,
+                                                        predIdx);
+    /* First loop block */
+    } else if ((numPred == 2) &&
+               dvmIsBitSet(bb->predecessors, cUnit->entryBlock->id)) {
+        while (true) {
+            int predIdx = dvmBitVectorIteratorNext(&bvIterator);
+            if (predIdx == cUnit->entryBlock->id) continue;
+            return (BasicBlock *) dvmGrowableListGetElement(&cUnit->blockList,
+                                                            predIdx);
+        }
+    /* Doesn't support other shape of control flow yet */
+    } else {
+        return NULL;
+    }
+}
+
 /*
  * A loop is considered optimizable if:
  * 1) It has one basic induction variable
@@ -171,11 +127,11 @@
  *
  * Return false if the loop is not optimizable.
  */
-static bool isLoopOptimizable(CompilationUnit *cUnit)
+static bool isSimpleCountedLoop(CompilationUnit *cUnit)
 {
     unsigned int i;
-    BasicBlock *loopBranch =
-        (BasicBlock *) dvmGrowableListGetElement(&cUnit->blockList, 2);
+    BasicBlock *loopBranch = findPredecessorBlock(cUnit,
+                                  cUnit->entryBlock->fallThrough);
     LoopAnalysis *loopAnalysis = cUnit->loopAnalysis;
 
     if (loopAnalysis->numBasicIV != 1) return false;
@@ -310,8 +266,7 @@
 /* Returns true if the loop body cannot throw any exceptions */
 static bool doLoopBodyCodeMotion(CompilationUnit *cUnit)
 {
-    BasicBlock *loopBody =
-        (BasicBlock *) dvmGrowableListGetElement(&cUnit->blockList, 1);
+    BasicBlock *loopBody = cUnit->entryBlock->fallThrough;
     MIR *mir;
     bool loopBodyCanThrow = false;
 
@@ -385,7 +340,7 @@
             if (dvmIsBitSet(cUnit->loopAnalysis->isIndVarV,
                             mir->ssaRep->uses[useIdx])) {
                 mir->OptimizationFlags |=
-                    MIR_IGNORE_RANGE_CHECK |  MIR_IGNORE_NULL_CHECK;
+                    MIR_IGNORE_RANGE_CHECK | MIR_IGNORE_NULL_CHECK;
                 updateRangeCheckInfo(cUnit, mir->ssaRep->uses[refIdx],
                                      mir->ssaRep->uses[useIdx]);
             }
@@ -398,8 +353,7 @@
 static void genHoistedChecks(CompilationUnit *cUnit)
 {
     unsigned int i;
-    BasicBlock *entry =
-        (BasicBlock *) dvmGrowableListGetElement(&cUnit->blockList, 0);
+    BasicBlock *entry = cUnit->entryBlock;
     LoopAnalysis *loopAnalysis = cUnit->loopAnalysis;
     int globalMaxC = 0;
     int globalMinC = 0;
@@ -460,14 +414,16 @@
             } else if (loopAnalysis->loopBranchOpcode == OP_IF_LTZ) {
                 /* Array index will fall below 0 */
                 if (globalMinC < 0) {
-                    MIR *boundCheckMIR = (MIR *)dvmCompilerNew(sizeof(MIR), true);
+                    MIR *boundCheckMIR = (MIR *)dvmCompilerNew(sizeof(MIR),
+                                                               true);
                     boundCheckMIR->dalvikInsn.opcode = kMirOpPunt;
                     dvmCompilerAppendMIR(entry, boundCheckMIR);
                 }
             } else if (loopAnalysis->loopBranchOpcode == OP_IF_LEZ) {
                 /* Array index will fall below 0 */
                 if (globalMinC < -1) {
-                    MIR *boundCheckMIR = (MIR *)dvmCompilerNew(sizeof(MIR), true);
+                    MIR *boundCheckMIR = (MIR *)dvmCompilerNew(sizeof(MIR),
+                                                               true);
                     boundCheckMIR->dalvikInsn.opcode = kMirOpPunt;
                     dvmCompilerAppendMIR(entry, boundCheckMIR);
                 }
@@ -480,79 +436,6 @@
     }
 }
 
-/*
- * Main entry point to do loop optimization.
- * Return false if sanity checks for loop formation/optimization failed.
- */
-bool dvmCompilerLoopOpt(CompilationUnit *cUnit)
-{
-    LoopAnalysis *loopAnalysis =
-        (LoopAnalysis *)dvmCompilerNew(sizeof(LoopAnalysis), true);
-
-    assert(((BasicBlock *) dvmGrowableListGetElement(&cUnit->blockList, 0))
-                               ->blockType == kTraceEntryBlock);
-    assert(((BasicBlock *) dvmGrowableListGetElement(&cUnit->blockList, 2))
-                               ->blockType == kDalvikByteCode);
-    assert(((BasicBlock *) dvmGrowableListGetElement(&cUnit->blockList, 3))
-                               ->blockType == kTraceExitBlock);
-
-    cUnit->loopAnalysis = loopAnalysis;
-    /*
-     * Find live-in variables to the loop body so that we can fake their
-     * definitions in the entry block.
-     */
-    dvmCompilerDataFlowAnalysisDispatcher(cUnit, dvmCompilerFindLocalLiveIn,
-                                          kAllNodes,
-                                          false /* isIterative */);
-
-    /* Insert phi nodes to the loop body */
-    handlePhiPlacement(cUnit);
-
-    dvmCompilerDataFlowAnalysisDispatcher(cUnit, dvmCompilerDoSSAConversion,
-                                          kAllNodes,
-                                          false /* isIterative */);
-    fillPhiNodeContents(cUnit);
-
-    /* Constant propagation */
-    cUnit->isConstantV = dvmAllocBitVector(cUnit->numSSARegs, false);
-    cUnit->constantValues =
-        (int *)dvmCompilerNew(sizeof(int) * cUnit->numSSARegs,
-                              true);
-    dvmCompilerDataFlowAnalysisDispatcher(cUnit,
-                                          dvmCompilerDoConstantPropagation,
-                                          kAllNodes,
-                                          false /* isIterative */);
-    DEBUG_LOOP(dumpConstants(cUnit);)
-
-    /* Find induction variables - basic and dependent */
-    loopAnalysis->ivList =
-        (GrowableList *)dvmCompilerNew(sizeof(GrowableList), true);
-    dvmInitGrowableList(loopAnalysis->ivList, 4);
-    loopAnalysis->isIndVarV = dvmAllocBitVector(cUnit->numSSARegs, false);
-    dvmCompilerDataFlowAnalysisDispatcher(cUnit,
-                                          dvmCompilerFindInductionVariables,
-                                          kAllNodes,
-                                          false /* isIterative */);
-    DEBUG_LOOP(dumpIVList(cUnit);)
-
-    /* If the loop turns out to be non-optimizable, return early */
-    if (!isLoopOptimizable(cUnit))
-        return false;
-
-    loopAnalysis->arrayAccessInfo =
-        (GrowableList *)dvmCompilerNew(sizeof(GrowableList), true);
-    dvmInitGrowableList(loopAnalysis->arrayAccessInfo, 4);
-    loopAnalysis->bodyIsClean = doLoopBodyCodeMotion(cUnit);
-    DEBUG_LOOP(dumpHoistedChecks(cUnit);)
-
-    /*
-     * Convert the array access information into extended MIR code in the loop
-     * header.
-     */
-    genHoistedChecks(cUnit);
-    return true;
-}
-
 void resetBlockEdges(BasicBlock *bb)
 {
     bb->taken = NULL;
@@ -573,53 +456,72 @@
 
     int numPred = dvmCountSetBits(firstBB->predecessors);
     /*
-     * A loop body should have at least two incoming edges. Here we go with the
-     * simple case and only form loops if numPred == 2.
+     * A loop body should have at least two incoming edges.
      */
-    if (numPred != 2) return false;
+    if (numPred < 2) return false;
 
-    BitVectorIterator bvIterator;
     GrowableList *blockList = &cUnit->blockList;
-    BasicBlock *predBB = NULL;
 
-    dvmBitVectorIteratorInit(firstBB->predecessors, &bvIterator);
-    while (true) {
-        int predIdx = dvmBitVectorIteratorNext(&bvIterator);
-        if (predIdx == -1) break;
-        predBB = (BasicBlock *) dvmGrowableListGetElement(blockList, predIdx);
-        if (predBB != cUnit->entryBlock) break;
-    }
-
-    /* Used to record which block is in the loop */
+    /* Record blocks included in the loop */
     dvmClearAllBits(cUnit->tempBlockV);
 
-    dvmCompilerSetBit(cUnit->tempBlockV, predBB->id);
+    dvmCompilerSetBit(cUnit->tempBlockV, cUnit->entryBlock->id);
+    dvmCompilerSetBit(cUnit->tempBlockV, firstBB->id);
 
-    /* Form a loop by only including iDom block that is also a predecessor */
-    while (predBB != firstBB) {
-        BasicBlock *iDom = predBB->iDom;
-        if (!dvmIsBitSet(predBB->predecessors, iDom->id)) {
-            return false;
-        /*
-         * And don't form nested loops (ie by detecting if the branch target
-         * of iDom dominates iDom).
-         */
-        } else if (iDom->taken &&
-                   dvmIsBitSet(iDom->dominators, iDom->taken->id) &&
-                   iDom != firstBB) {
+    BasicBlock *bodyBB = firstBB;
+
+    /*
+     * First try to include the fall-through block in the loop, then the taken
+     * block. Stop loop formation on the first backward branch that enters the
+     * first block (ie only include the inner-most loop).
+     */
+    while (true) {
+        /* Loop formed */
+        if (bodyBB->taken == firstBB || bodyBB->fallThrough == firstBB) break;
+
+        /* Inner loops formed first - quit */
+        if (bodyBB->fallThrough &&
+            dvmIsBitSet(cUnit->tempBlockV, bodyBB->fallThrough->id)) {
             return false;
         }
-        dvmCompilerSetBit(cUnit->tempBlockV, iDom->id);
-        predBB = iDom;
+        if (bodyBB->taken &&
+            dvmIsBitSet(cUnit->tempBlockV, bodyBB->taken->id)) {
+            return false;
+        }
+
+        if (bodyBB->fallThrough) {
+            if (bodyBB->fallThrough->iDom == bodyBB) {
+                bodyBB = bodyBB->fallThrough;
+                dvmCompilerSetBit(cUnit->tempBlockV, bodyBB->id);
+                /*
+                 * Loop formation to be detected at the beginning of next
+                 * iteration.
+                 */
+                continue;
+            }
+        }
+        if (bodyBB->taken) {
+            if (bodyBB->taken->iDom == bodyBB) {
+                bodyBB = bodyBB->taken;
+                dvmCompilerSetBit(cUnit->tempBlockV, bodyBB->id);
+                /*
+                 * Loop formation to be detected at the beginning of next
+                 * iteration.
+                 */
+                continue;
+            }
+        }
+        /*
+         * Current block is not the immediate dominator of either fallthrough
+         * nor taken block - bail out of loop formation.
+         */
+        return false;
     }
 
-    /* Add the entry block and first block */
-    dvmCompilerSetBit(cUnit->tempBlockV, firstBB->id);
-    dvmCompilerSetBit(cUnit->tempBlockV, cUnit->entryBlock->id);
 
     /* Now mark blocks not included in the loop as hidden */
     GrowableListIterator iterator;
-    dvmGrowableListIteratorInit(&cUnit->blockList, &iterator);
+    dvmGrowableListIteratorInit(blockList, &iterator);
     while (true) {
         BasicBlock *bb = (BasicBlock *) dvmGrowableListIteratorNext(&iterator);
         if (bb == NULL) break;
@@ -634,7 +536,7 @@
     dvmCompilerDataFlowAnalysisDispatcher(cUnit, clearPredecessorVector,
                                           kAllNodes, false /* isIterative */);
 
-    dvmGrowableListIteratorInit(&cUnit->blockList, &iterator);
+    dvmGrowableListIteratorInit(blockList, &iterator);
     while (true) {
         BasicBlock *bb = (BasicBlock *) dvmGrowableListIteratorNext(&iterator);
         if (bb == NULL) break;
@@ -671,6 +573,89 @@
             assert(bb->successorBlockList.blockListType == kNotUsed);
         }
     }
-
     return true;
 }
+
+/*
+ * Main entry point to do loop optimization.
+ * Return false if sanity checks for loop formation/optimization failed.
+ */
+bool dvmCompilerLoopOpt(CompilationUnit *cUnit)
+{
+    LoopAnalysis *loopAnalysis =
+        (LoopAnalysis *)dvmCompilerNew(sizeof(LoopAnalysis), true);
+    cUnit->loopAnalysis = loopAnalysis;
+
+    /* Constant propagation */
+    cUnit->isConstantV = dvmAllocBitVector(cUnit->numSSARegs, false);
+    cUnit->constantValues =
+        (int *)dvmCompilerNew(sizeof(int) * cUnit->numSSARegs,
+                              true);
+    dvmCompilerDataFlowAnalysisDispatcher(cUnit,
+                                          dvmCompilerDoConstantPropagation,
+                                          kAllNodes,
+                                          false /* isIterative */);
+    DEBUG_LOOP(dumpConstants(cUnit);)
+
+    /* Find induction variables - basic and dependent */
+    loopAnalysis->ivList =
+        (GrowableList *)dvmCompilerNew(sizeof(GrowableList), true);
+    dvmInitGrowableList(loopAnalysis->ivList, 4);
+    loopAnalysis->isIndVarV = dvmAllocBitVector(cUnit->numSSARegs, false);
+    dvmCompilerDataFlowAnalysisDispatcher(cUnit,
+                                          dvmCompilerFindInductionVariables,
+                                          kAllNodes,
+                                          false /* isIterative */);
+    DEBUG_LOOP(dumpIVList(cUnit);)
+
+    /* Only optimize array accesses for simple counted loop for now */
+    if (!isSimpleCountedLoop(cUnit))
+        return false;
+
+    loopAnalysis->arrayAccessInfo =
+        (GrowableList *)dvmCompilerNew(sizeof(GrowableList), true);
+    dvmInitGrowableList(loopAnalysis->arrayAccessInfo, 4);
+    loopAnalysis->bodyIsClean = doLoopBodyCodeMotion(cUnit);
+    DEBUG_LOOP(dumpHoistedChecks(cUnit);)
+
+    /*
+     * Convert the array access information into extended MIR code in the loop
+     * header.
+     */
+    genHoistedChecks(cUnit);
+    return true;
+}
+
+/*
+ * Select the target block of the backward branch.
+ */
+void dvmCompilerInsertBackwardChaining(CompilationUnit *cUnit)
+{
+    /*
+     * If we are not in self-verification or profiling mode, the backward
+     * branch can go to the entryBlock->fallThrough directly. Suspend polling
+     * code will be generated along the backward branch to honor the suspend
+     * requests.
+     */
+#if !defined(WITH_SELF_VERIFICATION)
+    if (gDvmJit.profileMode != kTraceProfilingContinuous &&
+        gDvmJit.profileMode != kTraceProfilingPeriodicOn) {
+        return;
+    }
+#endif
+    /*
+     * In self-verification or profiling mode, the backward branch is altered
+     * to go to the backward chaining cell. Without using the backward chaining
+     * cell we won't be able to do check-pointing on the target PC, or count the
+     * number of iterations accurately.
+     */
+    BasicBlock *firstBB = cUnit->entryBlock->fallThrough;
+    BasicBlock *backBranchBB = findPredecessorBlock(cUnit, firstBB);
+    if (backBranchBB->taken == firstBB) {
+        backBranchBB->taken = cUnit->backChainBlock;
+    } else {
+        assert(backBranchBB->fallThrough == firstBB);
+        backBranchBB->fallThrough = cUnit->backChainBlock;
+    }
+    cUnit->backChainBlock->startOffset = firstBB->startOffset;
+}
diff --git a/vm/compiler/Loop.h b/vm/compiler/Loop.h
index ec87e57..122817d 100644
--- a/vm/compiler/Loop.h
+++ b/vm/compiler/Loop.h
@@ -36,4 +36,13 @@
 
 bool dvmCompilerFilterLoopBlocks(CompilationUnit *cUnit);
 
+/*
+ * An unexecuted code path may contain unresolved fields or classes. Before we
+ * have a quiet resolver we simply bail out of the loop compilation mode.
+ */
+#define BAIL_LOOP_COMPILATION() if (cUnit->jitMode == kJitLoop) {       \
+                                    cUnit->quitLoopMode = true;         \
+                                    return false;                       \
+                                }
+
 #endif /* _DALVIK_VM_LOOP */
diff --git a/vm/compiler/Ralloc.c b/vm/compiler/Ralloc.c
index d772a31..e2752b1 100644
--- a/vm/compiler/Ralloc.c
+++ b/vm/compiler/Ralloc.c
@@ -27,8 +27,7 @@
 static void inferTypes(CompilationUnit *cUnit, BasicBlock *bb)
 {
     MIR *mir;
-    if (bb->blockType != kDalvikByteCode &&
-        bb->blockType != kTraceEntryBlock)
+    if (bb->blockType != kDalvikByteCode && bb->blockType != kEntryBlock)
         return;
 
     for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
diff --git a/vm/compiler/SSATransformation.c b/vm/compiler/SSATransformation.c
index b045a1e..6d7dd23 100644
--- a/vm/compiler/SSATransformation.c
+++ b/vm/compiler/SSATransformation.c
@@ -633,5 +633,9 @@
                                           kReachableNodes,
                                           false /* isIterative */);
 
+    if (gDvmJit.receivedSIGUSR2 || gDvmJit.printMe) {
+        dvmDumpCFG(cUnit, "/sdcard/cfg/");
+    }
+
     return true;
 }
diff --git a/vm/compiler/Utility.c b/vm/compiler/Utility.c
index fb16388..2599e0a 100644
--- a/vm/compiler/Utility.c
+++ b/vm/compiler/Utility.c
@@ -165,11 +165,9 @@
         "Backward Branch",
         "Chaining Cell Gap",
         "N/A",
-        "Method Entry Block",
-        "Trace Entry Block",
+        "Entry Block",
         "Code Block",
-        "Trace Exit Block",
-        "Method Exit Block",
+        "Exit Block",
         "PC Reconstruction",
         "Exception Handling",
     };
@@ -389,10 +387,10 @@
 void dvmGetBlockName(BasicBlock *bb, char *name)
 {
     switch (bb->blockType) {
-        case kMethodEntryBlock:
+        case kEntryBlock:
             snprintf(name, BLOCK_NAME_LEN, "entry");
             break;
-        case kMethodExitBlock:
+        case kExitBlock:
             snprintf(name, BLOCK_NAME_LEN, "exit");
             break;
         case kDalvikByteCode:
diff --git a/vm/compiler/codegen/arm/ArchUtility.c b/vm/compiler/codegen/arm/ArchUtility.c
index fb28e26..edcbf86 100644
--- a/vm/compiler/codegen/arm/ArchUtility.c
+++ b/vm/compiler/codegen/arm/ArchUtility.c
@@ -316,20 +316,25 @@
             DUMP_SSA_REP(LOGD("-------- %s\n", (char *) dest));
             break;
         case kArmPseudoChainingCellBackwardBranch:
+            LOGD("L%p:\n", lir);
             LOGD("-------- chaining cell (backward branch): 0x%04x\n", dest);
             break;
         case kArmPseudoChainingCellNormal:
+            LOGD("L%p:\n", lir);
             LOGD("-------- chaining cell (normal): 0x%04x\n", dest);
             break;
         case kArmPseudoChainingCellHot:
+            LOGD("L%p:\n", lir);
             LOGD("-------- chaining cell (hot): 0x%04x\n", dest);
             break;
         case kArmPseudoChainingCellInvokePredicted:
+            LOGD("L%p:\n", lir);
             LOGD("-------- chaining cell (predicted): %s%s\n",
                  dest ? ((Method *) dest)->clazz->descriptor : "",
                  dest ? ((Method *) dest)->name : "N/A");
             break;
         case kArmPseudoChainingCellInvokeSingleton:
+            LOGD("L%p:\n", lir);
             LOGD("-------- chaining cell (invoke singleton): %s%s/%p\n",
                  ((Method *)dest)->clazz->descriptor,
                  ((Method *)dest)->name,
diff --git a/vm/compiler/codegen/arm/Assemble.c b/vm/compiler/codegen/arm/Assemble.c
index 0e919c4..dfc68b6 100644
--- a/vm/compiler/codegen/arm/Assemble.c
+++ b/vm/compiler/codegen/arm/Assemble.c
@@ -1001,6 +1001,11 @@
                 lir->operands[1] = 0;
                 lir->generic.target = 0;
                 dvmCompilerSetupResourceMasks(lir);
+                if (cUnit->printMe) {
+                    LOGD("kThumb2Cbnz/kThumb2Cbz@%x: delta=%d",
+                         lir->generic.offset, delta);
+                    dvmCompilerCodegenDump(cUnit);
+                }
                 return kRetryAll;
             } else {
                 lir->operands[1] = delta >> 1;
diff --git a/vm/compiler/codegen/arm/CodegenDriver.c b/vm/compiler/codegen/arm/CodegenDriver.c
index 8d8619b..f020e9c 100644
--- a/vm/compiler/codegen/arm/CodegenDriver.c
+++ b/vm/compiler/codegen/arm/CodegenDriver.c
@@ -1356,6 +1356,12 @@
     int flagsToCheck = kInstrCanBranch | kInstrCanSwitch | kInstrCanReturn |
                        kInstrCanThrow;
 
+    // Single stepping is considered loop mode breaker
+    if (cUnit->jitMode == kJitLoop) {
+        cUnit->quitLoopMode = true;
+        return;
+    }
+
     //If already optimized out, just ignore
     if (mir->dalvikInsn.opcode == OP_NOP)
         return;
@@ -1448,7 +1454,8 @@
     /* backward branch? */
     bool backwardBranch = (bb->taken->startOffset <= mir->offset);
 
-    if (backwardBranch && gDvmJit.genSuspendPoll) {
+    if (backwardBranch &&
+        (gDvmJit.genSuspendPoll || cUnit->jitMode == kJitLoop)) {
         genSuspendPoll(cUnit, mir);
     }
 
@@ -1579,6 +1586,7 @@
               (cUnit->method->clazz->pDvmDex->pResStrings[mir->dalvikInsn.vB]);
 
             if (strPtr == NULL) {
+                BAIL_LOOP_COMPILATION();
                 LOGE("Unexpected null string");
                 dvmAbort();
             }
@@ -1595,6 +1603,7 @@
               (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
 
             if (classPtr == NULL) {
+                BAIL_LOOP_COMPILATION();
                 LOGE("Unexpected null class");
                 dvmAbort();
             }
@@ -1631,6 +1640,7 @@
             Opcode opcode = mir->dalvikInsn.opcode;
 
             if (fieldPtr == NULL) {
+                BAIL_LOOP_COMPILATION();
                 LOGE("Unexpected null static field");
                 dvmAbort();
             }
@@ -1664,6 +1674,7 @@
               (method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
 
             if (fieldPtr == NULL) {
+                BAIL_LOOP_COMPILATION();
                 LOGE("Unexpected null static field");
                 dvmAbort();
             }
@@ -1707,6 +1718,12 @@
               (method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
             Opcode opcode = mir->dalvikInsn.opcode;
 
+            if (fieldPtr == NULL) {
+                BAIL_LOOP_COMPILATION();
+                LOGE("Unexpected null static field");
+                dvmAbort();
+            }
+
             isVolatile = (opcode == OP_SPUT_VOLATILE) ||
                          (opcode == OP_SPUT_VOLATILE_JUMBO) ||
                          (opcode == OP_SPUT_OBJECT_VOLATILE) ||
@@ -1718,11 +1735,6 @@
                            (opcode == OP_SPUT_OBJECT_VOLATILE) ||
                            (opcode == OP_SPUT_OBJECT_VOLATILE_JUMBO);
 
-            if (fieldPtr == NULL) {
-                LOGE("Unexpected null static field");
-                dvmAbort();
-            }
-
             rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
             rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
             loadConstant(cUnit, tReg,  (int) fieldPtr);
@@ -1755,6 +1767,7 @@
               (method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
 
             if (fieldPtr == NULL) {
+                BAIL_LOOP_COMPILATION();
                 LOGE("Unexpected null static field");
                 dvmAbort();
             }
@@ -1778,6 +1791,7 @@
               (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
 
             if (classPtr == NULL) {
+                BAIL_LOOP_COMPILATION();
                 LOGE("Unexpected null class");
                 dvmAbort();
             }
@@ -1829,9 +1843,10 @@
              * so that we can tell if it happens frequently.
              */
             if (classPtr == NULL) {
-                 LOGVV("null clazz in OP_CHECK_CAST, single-stepping");
-                 genInterpSingleStep(cUnit, mir);
-                 return false;
+                BAIL_LOOP_COMPILATION();
+                LOGVV("null clazz in OP_CHECK_CAST, single-stepping");
+                genInterpSingleStep(cUnit, mir);
+                return false;
             }
             dvmCompilerFlushAllRegs(cUnit);   /* Everything to home location */
             loadConstant(cUnit, r1, (int) classPtr );
@@ -2093,7 +2108,8 @@
     /* backward branch? */
     bool backwardBranch = (bb->taken->startOffset <= mir->offset);
 
-    if (backwardBranch && gDvmJit.genSuspendPoll) {
+    if (backwardBranch &&
+        (gDvmJit.genSuspendPoll || cUnit->jitMode == kJitLoop)) {
         genSuspendPoll(cUnit, mir);
     }
 
@@ -2426,6 +2442,7 @@
                 method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vC];
 
             if (fieldPtr == NULL) {
+                BAIL_LOOP_COMPILATION();
                 LOGE("Unexpected null instance field");
                 dvmAbort();
             }
@@ -2448,6 +2465,7 @@
               (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]);
 
             if (classPtr == NULL) {
+                BAIL_LOOP_COMPILATION();
                 LOGE("Unexpected null class");
                 dvmAbort();
             }
@@ -2499,6 +2517,7 @@
              * so that we can tell if it happens frequently.
              */
             if (classPtr == NULL) {
+                BAIL_LOOP_COMPILATION();
                 LOGD("null clazz in OP_INSTANCE_OF, single-stepping");
                 genInterpSingleStep(cUnit, mir);
                 break;
@@ -2627,7 +2646,8 @@
     /* backward branch? */
     bool backwardBranch = (bb->taken->startOffset <= mir->offset);
 
-    if (backwardBranch && gDvmJit.genSuspendPoll) {
+    if (backwardBranch &&
+        (gDvmJit.genSuspendPoll || cUnit->jitMode == kJitLoop)) {
         genSuspendPoll(cUnit, mir);
     }
 
@@ -4238,7 +4258,7 @@
             dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[i]);
         }
 
-        if (bb->blockType == kTraceEntryBlock) {
+        if (bb->blockType == kEntryBlock) {
             labelList[i].opcode = kArmPseudoEntryBlock;
             if (bb->firstMIRInsn == NULL) {
                 continue;
@@ -4246,10 +4266,11 @@
               setupLoopEntryBlock(cUnit, bb,
                                   &labelList[bb->fallThrough->id]);
             }
-        } else if (bb->blockType == kTraceExitBlock) {
+        } else if (bb->blockType == kExitBlock) {
             labelList[i].opcode = kArmPseudoExitBlock;
             goto gen_fallthrough;
         } else if (bb->blockType == kDalvikByteCode) {
+            if (bb->hidden == true) continue;
             labelList[i].opcode = kArmPseudoNormalBlockLabel;
             /* Reset the register state */
             dvmCompilerResetRegPool(cUnit);
@@ -4297,8 +4318,8 @@
                     /* Make sure exception handling block is next */
                     labelList[i].opcode =
                         kArmPseudoPCReconstructionBlockLabel;
-                    assert (i == cUnit->numBlocks - 2);
-                    handlePCReconstruction(cUnit, &labelList[i+1]);
+                    handlePCReconstruction(cUnit,
+                                           &labelList[cUnit->puntBlock->id]);
                     break;
                 case kExceptionHandling:
                     labelList[i].opcode = kArmPseudoEHBlockLabel;
@@ -4510,7 +4531,7 @@
             }
         }
 
-        if (bb->blockType == kTraceEntryBlock) {
+        if (bb->blockType == kEntryBlock) {
             dvmCompilerAppendLIR(cUnit,
                                  (LIR *) cUnit->loopAnalysis->branchToBody);
             dvmCompilerAppendLIR(cUnit,
diff --git a/vm/compiler/codegen/arm/armv7-a-neon/MethodCodegenDriver.c b/vm/compiler/codegen/arm/armv7-a-neon/MethodCodegenDriver.c
index 5a08b60..98d97d8 100644
--- a/vm/compiler/codegen/arm/armv7-a-neon/MethodCodegenDriver.c
+++ b/vm/compiler/codegen/arm/armv7-a-neon/MethodCodegenDriver.c
@@ -255,13 +255,13 @@
 
     ArmLIR *headLIR = NULL;
 
-    if (bb->blockType == kMethodEntryBlock) {
+    if (bb->blockType == kEntryBlock) {
         /* r0 = callsitePC */
         opImm(cUnit, kOpPush, (1 << r0 | 1 << r1 | 1 << r5FP | 1 << r14lr));
         opRegImm(cUnit, kOpSub, r5FP,
                  sizeof(StackSaveArea) + cUnit->method->registersSize * 4);
 
-    } else if (bb->blockType == kMethodExitBlock) {
+    } else if (bb->blockType == kExitBlock) {
         /* No need to pop r0 and r1 */
         opRegImm(cUnit, kOpAdd, r13sp, 8);
         opImm(cUnit, kOpPop, (1 << r5FP | 1 << r15pc));
diff --git a/vm/hprof/Hprof.h b/vm/hprof/Hprof.h
index c79a3df..c62dd9c 100644
--- a/vm/hprof/Hprof.h
+++ b/vm/hprof/Hprof.h
@@ -84,12 +84,12 @@
     /* Android */
     HPROF_HEAP_DUMP_INFO = 0xfe,
     HPROF_ROOT_INTERNED_STRING = 0x89,
-    HPROF_ROOT_FINALIZING = 0x8a,
+    HPROF_ROOT_FINALIZING = 0x8a,  /* obsolete */
     HPROF_ROOT_DEBUGGER = 0x8b,
-    HPROF_ROOT_REFERENCE_CLEANUP = 0x8c,
+    HPROF_ROOT_REFERENCE_CLEANUP = 0x8c,  /* obsolete */
     HPROF_ROOT_VM_INTERNAL = 0x8d,
     HPROF_ROOT_JNI_MONITOR = 0x8e,
-    HPROF_UNREACHABLE = 0x90,  /* deprecated */
+    HPROF_UNREACHABLE = 0x90,  /* obsolete */
     HPROF_PRIMITIVE_ARRAY_NODATA_DUMP = 0xc3,
 } hprof_heap_tag_t;