Tear down the code cache when it is full and restart from scratch.

Because the code cache may be wiped out after safe points now the patching of
inline cache for predicted chains is done through the compiler thread's work
queue.
diff --git a/vm/compiler/codegen/arm/Assemble.c b/vm/compiler/codegen/arm/Assemble.c
index 26e227f..7444b3e 100644
--- a/vm/compiler/codegen/arm/Assemble.c
+++ b/vm/compiler/codegen/arm/Assemble.c
@@ -1407,35 +1407,65 @@
      */
     cell->counter = PREDICTED_CHAIN_COUNTER_AVOID;
 
-    /* Stop the world */
-    dvmSuspendAllThreads(SUSPEND_FOR_IC_PATCH);
+    PredictedChainingCell *newCell =
+        (PredictedChainingCell *) malloc(sizeof(PredictedChainingCell));
 
     int baseAddr = (int) cell + 4;   // PC is cur_addr + 4
     int branchOffset = tgtAddr - baseAddr;
 
-    COMPILER_TRACE_CHAINING(
-        LOGD("Jit Runtime: predicted chain %p from %s to %s (%s) patched",
-             cell, cell->clazz ? cell->clazz->descriptor : "NULL",
-             clazz->descriptor,
-             method->name));
+    newCell->branch = assembleChainingBranch(branchOffset, true);
+    newCell->clazz = clazz;
+    newCell->method = method;
 
-    cell->branch = assembleChainingBranch(branchOffset, true);
-    cell->clazz = clazz;
-    cell->method = method;
     /*
      * Reset the counter again in case other mutator threads got invoked
      * between the previous rest and dvmSuspendAllThreads call.
      */
-    cell->counter = PREDICTED_CHAIN_COUNTER_RECHAIN;
+    newCell->counter = PREDICTED_CHAIN_COUNTER_RECHAIN;
 
-    cacheflush((long) cell, (long) (cell+1), 0);
+    /*
+     * Enter the work order to the queue for the compiler thread to patch the
+     * chaining cell.
+     *
+     * No blocking call is added here because the patched result is not
+     * intended to be immediately consumed by the requesting thread. Its
+     * execution is simply resumed by chasing the class pointer to resolve the
+     * callsite.
+     */
+    dvmCompilerWorkEnqueue((const u2 *) cell, kWorkOrderICPatch, newCell);
+#endif
+done:
+    return method;
+}
+
+/*
+ * Patch the inline cache content based on the content passed from the work
+ * order.
+ */
+bool dvmJitPatchInlineCache(void *cellPtr, void *contentPtr)
+{
+    PredictedChainingCell *cellDest = (PredictedChainingCell *) cellPtr;
+    PredictedChainingCell *newContent = (PredictedChainingCell *) contentPtr;
+
+    /* Stop the world */
+    dvmSuspendAllThreads(SUSPEND_FOR_IC_PATCH);
+
+    COMPILER_TRACE_CHAINING(
+        LOGD("Jit Runtime: predicted chain %p from %s to %s (%s) patched",
+             cellDest, cellDest->clazz ? cellDest->clazz->descriptor : "NULL",
+             newContent->clazz->descriptor,
+             newContent->method->name));
+
+    /* Install the new cell content */
+    *cellDest = *newContent;
+
+    /* Then synchronize the I/D$ */
+    cacheflush((long) cellDest, (long) (cellDest+1), 0);
 
     /* All done - resume all other threads */
     dvmResumeAllThreads(SUSPEND_FOR_IC_PATCH);
-#endif
 
-done:
-    return method;
+    return true;
 }
 
 /*
diff --git a/vm/compiler/codegen/arm/CodegenDriver.c b/vm/compiler/codegen/arm/CodegenDriver.c
index f3648b9..010e8ca 100644
--- a/vm/compiler/codegen/arm/CodegenDriver.c
+++ b/vm/compiler/codegen/arm/CodegenDriver.c
@@ -4117,6 +4117,9 @@
             gDvmJit.printMe = oldPrintMe;;
             break;
         }
+        case kWorkOrderICPatch:
+            res = dvmJitPatchInlineCache((void *) work->pc, work->info);
+            break;
         default:
             res = false;
             dvmAbort();