Merge "Fix the handful of leaks detectable in our tests." into dalvik-dev
diff --git a/src/compiled_method.cc b/src/compiled_method.cc
index 40230b4..ca7858a 100644
--- a/src/compiled_method.cc
+++ b/src/compiled_method.cc
@@ -50,22 +50,7 @@
   CHECK_NE(mapping_table_.size(), 0U);
   CHECK_NE(vmap_table_.size(), 0U);
 
-  std::vector<uint8_t> length_prefixed_gc_map;
-  length_prefixed_gc_map.push_back((gc_map.size() & 0xff000000) >> 24);
-  length_prefixed_gc_map.push_back((gc_map.size() & 0x00ff0000) >> 16);
-  length_prefixed_gc_map.push_back((gc_map.size() & 0x0000ff00) >> 8);
-  length_prefixed_gc_map.push_back((gc_map.size() & 0x000000ff) >> 0);
-  length_prefixed_gc_map.insert(length_prefixed_gc_map.end(),
-                                gc_map.begin(),
-                                gc_map.end());
-  DCHECK_EQ(gc_map.size() + 4, length_prefixed_gc_map.size());
-  DCHECK_EQ(gc_map.size(),
-            static_cast<size_t>((length_prefixed_gc_map[0] << 24) |
-                                (length_prefixed_gc_map[1] << 16) |
-                                (length_prefixed_gc_map[2] << 8) |
-                                (length_prefixed_gc_map[3] << 0)));
-
-  gc_map_ = length_prefixed_gc_map;
+  gc_map_ = gc_map;
 }
 
 CompiledMethod::CompiledMethod(InstructionSet instruction_set,
diff --git a/src/compiler/Frontend.cc b/src/compiler/Frontend.cc
index 2eba586..5be51f4 100644
--- a/src/compiler/Frontend.cc
+++ b/src/compiler/Frontend.cc
@@ -115,7 +115,8 @@
 /* Split an existing block from the specified code offset into two */
 STATIC BasicBlock *splitBlock(CompilationUnit* cUnit,
                               unsigned int codeOffset,
-                              BasicBlock* origBlock)
+                              BasicBlock* origBlock,
+                              BasicBlock** immedPredBlockP)
 {
     MIR* insn = origBlock->firstMIRInsn;
     while (insn) {
@@ -176,16 +177,28 @@
 
     insn->prev->next = NULL;
     insn->prev = NULL;
+    /*
+     * Update the immediate predecessor block pointer so that outgoing edges
+     * can be applied to the proper block.
+     */
+    if (immedPredBlockP) {
+        DCHECK_EQ(*immedPredBlockP, origBlock);
+        *immedPredBlockP = bottomBlock;
+    }
     return bottomBlock;
 }
 
 /*
  * Given a code offset, find out the block that starts with it. If the offset
- * is in the middle of an existing block, split it into two.
+ * is in the middle of an existing block, split it into two.  If immedPredBlockP
+ * is not non-null and is the block being split, update *immedPredBlockP to
+ * point to the bottom block so that outgoing edges can be set up properly
+ * (by the caller)
  */
 STATIC BasicBlock *findBlock(CompilationUnit* cUnit,
                              unsigned int codeOffset,
-                             bool split, bool create)
+                             bool split, bool create,
+                             BasicBlock** immedPredBlockP)
 {
     GrowableList* blockList = &cUnit->blockList;
     BasicBlock* bb;
@@ -199,7 +212,9 @@
         if ((split == true) && (codeOffset > bb->startOffset) &&
             (bb->lastMIRInsn != NULL) &&
             (codeOffset <= bb->lastMIRInsn->offset)) {
-            BasicBlock *newBB = splitBlock(cUnit, codeOffset, bb);
+            BasicBlock *newBB = splitBlock(cUnit, codeOffset, bb,
+                                           bb == *immedPredBlockP ?
+                                           immedPredBlockP : NULL);
             return newBB;
         }
     }
@@ -445,7 +460,8 @@
         art::CatchHandlerIterator iterator(handlers_ptr);
         for (; iterator.HasNext(); iterator.Next()) {
             uint32_t address = iterator.GetHandlerAddress();
-            findBlock(cUnit, address, false /* split */, true /*create*/);
+            findBlock(cUnit, address, false /* split */, true /*create*/,
+                      /* immedPredBlockP */ NULL);
         }
         handlers_ptr = iterator.EndDataPointer();
     }
@@ -484,22 +500,13 @@
             LOG(FATAL) << "Unexpected opcode(" << (int)insn->dalvikInsn.opcode
                 << ") with kInstrCanBranch set";
     }
-    /*
-     * Some ugliness here.  It is possible that findBlock will
-     * split the current block.  In that case, we need to operate
-     * on the 2nd half on the split pair.  It isn't directly obvious
-     * when this happens, so we infer.
-     */
-    DCHECK(curBlock->lastMIRInsn == insn);
     BasicBlock *takenBlock = findBlock(cUnit, target,
                                        /* split */
                                        true,
                                        /* create */
-                                       true);
-     if (curBlock->lastMIRInsn != insn) {
-         DCHECK(takenBlock->lastMIRInsn == insn);
-         curBlock = curBlock->fallThrough;
-    }
+                                       true,
+                                       /* immedPredBlockP */
+                                       &curBlock);
     curBlock->taken = takenBlock;
     oatSetBit(takenBlock->predecessors, curBlock->id);
 
@@ -521,7 +528,9 @@
                                                   */
                                                  true,
                                                  /* create */
-                                                 true);
+                                                 true,
+                                                 /* immedPredBlockP */
+                                                 &curBlock);
         curBlock->fallThrough = fallthroughBlock;
         oatSetBit(fallthroughBlock->predecessors, curBlock->id);
     } else if (codePtr < codeEnd) {
@@ -531,7 +540,9 @@
                       /* split */
                       false,
                       /* create */
-                      true);
+                      true,
+                      /* immedPredBlockP */
+                      NULL);
         }
     }
     return curBlock;
@@ -595,7 +606,9 @@
                                           /* split */
                                           true,
                                           /* create */
-                                          true);
+                                          true,
+                                          /* immedPredBlockP */
+                                          &curBlock);
         SuccessorBlockInfo *successorBlockInfo =
             (SuccessorBlockInfo *) oatNew(sizeof(SuccessorBlockInfo),
                                                   false);
@@ -613,7 +626,9 @@
                                              /* split */
                                              false,
                                              /* create */
-                                             true);
+                                             true,
+                                             /* immedPredBlockP */
+                                             NULL);
     curBlock->fallThrough = fallthroughBlock;
     oatSetBit(fallthroughBlock->predecessors, curBlock->id);
 }
@@ -641,7 +656,8 @@
         for (;iterator.HasNext(); iterator.Next()) {
             BasicBlock *catchBlock = findBlock(cUnit, iterator.GetHandlerAddress(),
                                                false /* split*/,
-                                               false /* creat */);
+                                               false /* creat */,
+                                               NULL  /* immedPredBlockP */);
             catchBlock->catchEntry = true;
             SuccessorBlockInfo *successorBlockInfo =
                   (SuccessorBlockInfo *) oatNew(sizeof(SuccessorBlockInfo),
@@ -675,7 +691,9 @@
                                                      /* split */
                                                      false,
                                                      /* create */
-                                                     true);
+                                                     true,
+                                                     /* immedPredBlockP */
+                                                     NULL);
             /*
              * OP_THROW is an unconditional branch.  NOTE:
              * OP_THROW_VERIFICATION_ERROR is also an unconditional
@@ -822,7 +840,9 @@
                               /* split */
                               false,
                               /* create */
-                              true);
+                              true,
+                              /* immedPredBlockP */
+                              NULL);
                 }
             }
         } else if (flags & kInstrCanThrow) {
@@ -836,7 +856,9 @@
                                           /* split */
                                           false,
                                           /* create */
-                                          false);
+                                          false,
+                                          /* immedPredBlockP */
+                                          NULL);
         if (nextBlock) {
             /*
              * The next instruction could be the target of a previously parsed
diff --git a/src/dalvik_system_VMRuntime.cc b/src/dalvik_system_VMRuntime.cc
index 3a1eac0..5dcbb41 100644
--- a/src/dalvik_system_VMRuntime.cc
+++ b/src/dalvik_system_VMRuntime.cc
@@ -117,7 +117,8 @@
   if (targetSdkVersion > 0 && targetSdkVersion <= 13 /* honeycomb-mr2 */) {
     // TODO: running with CheckJNI should override this and force you to obey the strictest rules.
     LOG(INFO) << "Turning on JNI app bug workarounds for target SDK version " << targetSdkVersion << "...";
-    Runtime::Current()->GetJavaVM()->work_around_app_jni_bugs = true;
+    // Runtime::Current()->GetJavaVM()->work_around_app_jni_bugs = true;
+    UNIMPLEMENTED(WARNING) << "Support work arounds for app JNI bugs";
   }
 }
 
diff --git a/src/dex_verifier.cc b/src/dex_verifier.cc
index c219042..deffdc2 100644
--- a/src/dex_verifier.cc
+++ b/src/dex_verifier.cc
@@ -24,7 +24,22 @@
 static const bool gDebugVerify = false;
 
 std::ostream& operator<<(std::ostream& os, const VerifyError& rhs) {
-  return os << (int)rhs;
+  switch (rhs) {
+  case VERIFY_ERROR_NONE: os << "VERIFY_ERROR_NONE"; break;
+  case VERIFY_ERROR_GENERIC: os << "VERIFY_ERROR_GENERIC"; break;
+  case VERIFY_ERROR_NO_CLASS: os << "VERIFY_ERROR_NO_CLASS"; break;
+  case VERIFY_ERROR_NO_FIELD: os << "VERIFY_ERROR_NO_FIELD"; break;
+  case VERIFY_ERROR_NO_METHOD: os << "VERIFY_ERROR_NO_METHOD"; break;
+  case VERIFY_ERROR_ACCESS_CLASS: os << "VERIFY_ERROR_ACCESS_CLASS"; break;
+  case VERIFY_ERROR_ACCESS_FIELD: os << "VERIFY_ERROR_ACCESS_FIELD"; break;
+  case VERIFY_ERROR_ACCESS_METHOD: os << "VERIFY_ERROR_ACCESS_METHOD"; break;
+  case VERIFY_ERROR_CLASS_CHANGE: os << "VERIFY_ERROR_CLASS_CHANGE"; break;
+  case VERIFY_ERROR_INSTANTIATION: os << "VERIFY_ERROR_INSTANTIATION"; break;
+  default:
+    os << "VerifyError[" << static_cast<int>(rhs) << "]";
+    break;
+  }
+  return os;
 }
 
 static const char* type_strings[] = {
@@ -941,6 +956,8 @@
 bool DexVerifier::VerifyMethod(Method* method) {
   DexVerifier verifier(method);
   bool success = verifier.Verify();
+  CHECK_EQ(success, verifier.failure_ == VERIFY_ERROR_NONE);
+
   // We expect either success and no verification error, or failure and a generic failure to
   // reject the class.
   if (success) {
@@ -1496,6 +1513,24 @@
   return true;
 }
 
+const std::vector<uint8_t>* CreateLengthPrefixedGcMap(const std::vector<uint8_t>& gc_map) {
+  std::vector<uint8_t>* length_prefixed_gc_map = new std::vector<uint8_t>;
+  length_prefixed_gc_map->push_back((gc_map.size() & 0xff000000) >> 24);
+  length_prefixed_gc_map->push_back((gc_map.size() & 0x00ff0000) >> 16);
+  length_prefixed_gc_map->push_back((gc_map.size() & 0x0000ff00) >> 8);
+  length_prefixed_gc_map->push_back((gc_map.size() & 0x000000ff) >> 0);
+  length_prefixed_gc_map->insert(length_prefixed_gc_map->end(),
+                                 gc_map.begin(),
+                                 gc_map.end());
+  DCHECK_EQ(gc_map.size() + 4, length_prefixed_gc_map->size());
+  DCHECK_EQ(gc_map.size(),
+            static_cast<size_t>((length_prefixed_gc_map->at(0) << 24) |
+                                (length_prefixed_gc_map->at(1) << 16) |
+                                (length_prefixed_gc_map->at(2) << 8) |
+                                (length_prefixed_gc_map->at(3) << 0)));
+  return length_prefixed_gc_map;
+}
+
 bool DexVerifier::VerifyCodeFlow() {
   uint16_t registers_size = code_item_->registers_size_;
   uint32_t insns_size = code_item_->insns_size_in_code_units_;
@@ -1519,19 +1554,23 @@
   }
   /* Perform code flow verification. */
   if (!CodeFlowVerifyMethod()) {
+    DCHECK_NE(failure_, VERIFY_ERROR_NONE);
     return false;
   }
 
   /* Generate a register map and add it to the method. */
-  const std::vector<uint8_t>* map = GenerateGcMap();
-  if (map == NULL) {
+  UniquePtr<const std::vector<uint8_t> > map(GenerateGcMap());
+  if (map.get() == NULL) {
+    DCHECK_NE(failure_, VERIFY_ERROR_NONE);
     return false;  // Not a real failure, but a failure to encode
   }
-  Compiler::MethodReference ref(dex_file_, method_->GetDexMethodIndex());
-  verifier::DexVerifier::SetGcMap(ref, *map);
 #ifndef NDEBUG
   VerifyGcMap(*map);
 #endif
+  const std::vector<uint8_t>* gc_map = CreateLengthPrefixedGcMap(*(map.get()));
+  Compiler::MethodReference ref(dex_file_, method_->GetDexMethodIndex());
+  verifier::DexVerifier::SetGcMap(ref, *gc_map);
+  method_->SetGcMap(&gc_map->at(0));
   return true;
 }
 
diff --git a/test/083-jit-regressions/expected.txt b/test/083-jit-regressions/expected.txt
index 1f30d21..4b9ad5b 100644
--- a/test/083-jit-regressions/expected.txt
+++ b/test/083-jit-regressions/expected.txt
@@ -1,3 +1,4 @@
 b2296099 passes
 b2302318 passes
 b2487514 passes
+b5884080 passes
diff --git a/test/083-jit-regressions/info.txt b/test/083-jit-regressions/info.txt
index b791aba..00c24ee 100644
--- a/test/083-jit-regressions/info.txt
+++ b/test/083-jit-regressions/info.txt
@@ -8,3 +8,4 @@
 2296099 JIT shift bug
 2302318 Crash during spin-on-suspend testing
 2487514 Missed exception in PriorityBlockingQueueTest.testToArray1_BadArg
+5884080 ICS JIT regression in nested loop formation
diff --git a/test/083-jit-regressions/src/Main.java b/test/083-jit-regressions/src/Main.java
index 1f1dee3..3b596db 100644
--- a/test/083-jit-regressions/src/Main.java
+++ b/test/083-jit-regressions/src/Main.java
@@ -24,6 +24,7 @@
         b2296099Test();
         b2302318Test();
         b2487514Test();
+        b5884080Test();
     }
 
     static void b2296099Test() throws Exception {
@@ -105,6 +106,26 @@
                                " (expecting 1000)");
         }
     }
+
+    static void b5884080Test() {
+        int vA = 1;
+
+        int l = 0;
+        do
+        {
+            int k = 0;
+            do
+                vA += 1;
+            while(++k < 100);
+        } while(++l < 1000);
+        if (vA == 100001) {
+            System.out.println("b5884080 passes");
+        }
+        else {
+            System.out.println("b5884080 fails: vA is " + vA +
+                               " (expecting 100001)");
+        }
+    }
 }
 
 class SpinThread extends Thread {