Merge "Remove sorted variable in allocation stacks." into dalvik-dev
diff --git a/build/Android.common.mk b/build/Android.common.mk
index bfb1f9b..8209725 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -14,6 +14,9 @@
 # limitations under the License.
 #
 
+ifndef ANDROID_COMMON_MK
+ANDROID_COMMON_MK = true
+
 # These can be overridden via the environment or by editing to
 # enable/disable certain build configuration.
 #
@@ -163,11 +166,8 @@
 else
   # Warn if not using GCC 4.6 for target builds when not doing a top-level or 'mma' build.
   ifneq ($(ONE_SHOT_MAKEFILE),)
-    ifneq ($(ART_THREAD_SAFETY_CHECK_WARNING),true)
-      # Enable target GCC 4.6 with: export TARGET_GCC_VERSION_EXP=4.6
-      $(info Using target GCC $(TARGET_GCC_VERSION) disables thread-safety checks.)
-      ART_THREAD_SAFETY_CHECK_WARNING := true
-    endif
+    # Enable target GCC 4.6 with: export TARGET_GCC_VERSION_EXP=4.6
+    $(info Using target GCC $(TARGET_GCC_VERSION) disables thread-safety checks.)
   endif
 endif
 # We build with GCC 4.6 on the host.
@@ -219,3 +219,5 @@
   ART_BUILD_HOST := true
   ART_BUILD_DEBUG := true
 endif
+
+endif # ANDROID_COMMON_MK
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index 994d43e..4648d44 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -44,6 +44,7 @@
 	runtime/indirect_reference_table_test.cc \
 	runtime/intern_table_test.cc \
 	runtime/jni_internal_test.cc \
+	runtime/mem_map_test.cc \
 	runtime/mirror/dex_cache_test.cc \
 	runtime/mirror/object_test.cc \
 	runtime/oat_test.cc \
diff --git a/compiler/sea_ir/instruction_nodes.h b/compiler/sea_ir/instruction_nodes.h
index 103c16f..6f9bddd 100644
--- a/compiler/sea_ir/instruction_nodes.h
+++ b/compiler/sea_ir/instruction_nodes.h
@@ -57,6 +57,7 @@
   // essentially creating SSA form.
   void RenameToSSA(int reg_no, InstructionNode* definition) {
     definition_edges_.insert(std::pair<int, InstructionNode*>(reg_no, definition));
+    definition->AddSSAUse(this);
   }
   // Returns the ordered set of Instructions that define the input operands of this instruction.
   // Precondition: SeaGraph.ConvertToSSA().
@@ -69,6 +70,10 @@
     return ssa_uses;
   }
 
+  virtual void AddSSAUse(InstructionNode* use) {
+    used_in_.push_back(use);
+  }
+
   void Accept(IRVisitor* v) {
     v->Visit(this);
     v->Traverse(this);
@@ -85,11 +90,14 @@
 
  protected:
   explicit InstructionNode(const art::Instruction* in):
-      SeaNode(), instruction_(in), de_def_(false), region_(NULL) { }
+      SeaNode(), instruction_(in), used_in_(), de_def_(false), region_(NULL) { }
+  void ToDotSSAEdges(std::string& result) const;
 
  protected:
   const art::Instruction* const instruction_;
   std::map<int, InstructionNode* > definition_edges_;
+  // Stores pointers to instructions that use the result of the current instruction.
+  std::vector<InstructionNode*> used_in_;
   bool de_def_;
   Region* region_;
 };
@@ -136,15 +144,7 @@
       result += "style=bold";
     }
     result += "];\n";
-    // SSA definitions:
-    for (std::map<int, InstructionNode* >::const_iterator def_it = definition_edges_.begin();
-        def_it != definition_edges_.end(); def_it++) {
-      if (NULL != def_it->second) {
-        result += def_it->second->StringId() + " -> " + StringId() +"[color=gray,label=\"";
-        result += art::StringPrintf("vR = %d", def_it->first);
-        result += "\"] ; // ssa edge\n";
-      }
-    }
+    ToDotSSAEdges(result);
   }
 
  private:
diff --git a/compiler/sea_ir/sea.cc b/compiler/sea_ir/sea.cc
index e9a3e1c..99b21f8 100644
--- a/compiler/sea_ir/sea.cc
+++ b/compiler/sea_ir/sea.cc
@@ -692,6 +692,27 @@
   return sea_instructions;
 }
 
+void InstructionNode::ToDotSSAEdges(std::string& result) const {
+  // SSA definitions:
+  for (std::map<int, InstructionNode*>::const_iterator def_it = definition_edges_.begin();
+      def_it != definition_edges_.end(); def_it++) {
+    if (NULL != def_it->second) {
+      result += def_it->second->StringId() + " -> " + StringId() + "[color=gray,label=\"";
+      result += art::StringPrintf("vR = %d", def_it->first);
+      result += "\"] ; // ssa edge\n";
+    }
+  }
+
+  // SSA used-by:
+  if (DotConversion::SaveUseEdges()) {
+    for (std::vector<InstructionNode*>::const_iterator cit = used_in_.begin();
+        cit != used_in_.end(); cit++) {
+      result += (*cit)->StringId() + " -> " + StringId() + "[color=gray,label=\"";
+      result += "\"] ; // SSA used-by edge\n";
+    }
+  }
+}
+
 void InstructionNode::ToDot(std::string& result, const art::DexFile& dex_file) const {
   result += "// Instruction ("+StringId()+"): \n" + StringId() +
       " [label=\"" + instruction_->DumpString(&dex_file) + "\"";
@@ -699,15 +720,8 @@
     result += "style=bold";
   }
   result += "];\n";
-  // SSA definitions:
-  for (std::map<int, InstructionNode* >::const_iterator def_it = definition_edges_.begin();
-      def_it != definition_edges_.end(); def_it++) {
-    if (NULL != def_it->second) {
-      result += def_it->second->StringId() + " -> " + StringId() +"[color=gray,label=\"";
-      result += art::StringPrintf("vR = %d", def_it->first);
-      result += "\"] ; // ssa edge\n";
-    }
-  }
+
+  ToDotSSAEdges(result);
 }
 
 void InstructionNode::MarkAsDEDef() {
@@ -756,17 +770,6 @@
   result += art::StringPrintf("%d", register_no_);
   result += ")\"";
   result += "];\n";
-
-  for (std::vector<std::vector<InstructionNode*>*>::const_iterator pred_it =
-      definition_edges_.begin();
-      pred_it != definition_edges_.end(); pred_it++) {
-    std::vector<InstructionNode*>* defs_from_pred = *pred_it;
-    for (std::vector<InstructionNode* >::const_iterator def_it = defs_from_pred->begin();
-        def_it != defs_from_pred->end(); def_it++) {
-        result += (*def_it)->StringId() + " -> " + StringId() +"[color=gray,label=\"vR = ";
-        result += art::StringPrintf("%d", GetRegisterNumber());
-        result += "\"] ;  // phi-ssa edge\n";
-    }
-  }
+  ToDotSSAEdges(result);
 }
 }  // namespace sea_ir
diff --git a/compiler/sea_ir/sea.h b/compiler/sea_ir/sea.h
index c64703a..5cb8424 100644
--- a/compiler/sea_ir/sea.h
+++ b/compiler/sea_ir/sea.h
@@ -35,6 +35,17 @@
   VISITING = -2
 };
 
+// Stores options for turning a SEA IR graph to a .dot file.
+class DotConversion {
+ public:
+  static bool SaveUseEdges() {
+    return save_use_edges_;
+  }
+
+ private:
+  static const bool save_use_edges_ =  false;  // TODO: Enable per-sea graph configuration.
+};
+
 class Region;
 
 class InstructionNode;
@@ -53,6 +64,7 @@
     result += StringId() +" [label=\"signature:";
     result += art::StringPrintf("r%d", GetResultRegister());
     result += "\"] // signature node\n";
+    ToDotSSAEdges(result);
   }
 
   int GetResultRegister() const {
@@ -98,6 +110,7 @@
       definition_edges_[predecessor_id] = new std::vector<InstructionNode*>();
     }
     definition_edges_[predecessor_id]->push_back(definition);
+    definition->AddSSAUse(this);
   }
 
   // Returns the instruction that defines the phi register from predecessor
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 40033b7..72e0f48 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -1022,15 +1022,19 @@
     return;
   }
 
-  // Set entry points to interpreter for methods in interpreter only mode.
   if (obj->IsMethod()) {
     mirror::AbstractMethod* method = obj->AsMethod();
+    // Set entry points to interpreter for methods in interpreter only mode.
     if (Runtime::Current()->GetInstrumentation()->InterpretOnly() && !method->IsNative()) {
       method->SetEntryPointFromInterpreter(interpreter::artInterpreterToInterpreterEntry);
       if (method != Runtime::Current()->GetResolutionMethod()) {
         method->SetEntryPointFromCompiledCode(GetInterpreterEntryPoint());
       }
     }
+    // Populate native method pointer with jni lookup stub.
+    if (method->IsNative()) {
+      method->UnregisterNative(Thread::Current());
+    }
   }
 }
 
@@ -1523,6 +1527,13 @@
 // Special case to get oat code without overwriting a trampoline.
 const void* ClassLinker::GetOatCodeFor(const mirror::AbstractMethod* method) {
   CHECK(!method->IsAbstract()) << PrettyMethod(method);
+  if (method->IsProxyMethod()) {
+#if !defined(ART_USE_PORTABLE_COMPILER)
+    return reinterpret_cast<void*>(art_quick_proxy_invoke_handler);
+#else
+    return reinterpret_cast<void*>(art_portable_proxy_invoke_handler);
+#endif
+  }
   const void* result = GetOatMethodFor(method).GetCode();
   if (result == NULL) {
     // No code? You must mean to go into the interpreter.
diff --git a/runtime/indirect_reference_table.cc b/runtime/indirect_reference_table.cc
index 0616d28..3e75716 100644
--- a/runtime/indirect_reference_table.cc
+++ b/runtime/indirect_reference_table.cc
@@ -237,7 +237,7 @@
     mirror::Object* direct_pointer = reinterpret_cast<mirror::Object*>(iref);
     idx = Find(direct_pointer, bottomIndex, topIndex, table_);
     if (idx == -1) {
-      LOG(WARNING) << "trying to work around app JNI bugs, but didn't find " << iref << " in table!";
+      LOG(WARNING) << "Trying to work around app JNI bugs, but didn't find " << iref << " in table!";
       return false;
     }
   }
diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc
index 8d7d028..37c45fa 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -975,7 +975,9 @@
   self->VerifyStack();
   ThrowLocation throw_location;
   mirror::Throwable* exception = self->GetException(&throw_location);
-  uint32_t found_dex_pc = shadow_frame.GetMethod()->FindCatchBlock(exception->GetClass(), dex_pc);
+  bool clear_exception;
+  uint32_t found_dex_pc = shadow_frame.GetMethod()->FindCatchBlock(exception->GetClass(), dex_pc,
+                                                                   &clear_exception);
   if (found_dex_pc == DexFile::kDexNoIndex) {
     instrumentation->MethodUnwindEvent(self, this_object_ref.get(),
                                        shadow_frame.GetMethod(), dex_pc);
@@ -984,6 +986,9 @@
     instrumentation->ExceptionCaughtEvent(self, throw_location,
                                           shadow_frame.GetMethod(),
                                           found_dex_pc, exception);
+    if (clear_exception) {
+      self->ClearException();
+    }
     return Instruction::At(insns + found_dex_pc);
   }
 }
diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc
index 858ac34..6681d56 100644
--- a/runtime/jni_internal.cc
+++ b/runtime/jni_internal.cc
@@ -833,11 +833,7 @@
       return NULL;
     }
     ScopedObjectAccess soa(env);
-    IndirectReferenceTable& locals = soa.Env()->locals;
-
-    uint32_t cookie = soa.Env()->local_ref_cookie;
-    IndirectRef ref = locals.Add(cookie, soa.Decode<Object*>(obj));
-    return reinterpret_cast<jobject>(ref);
+    return soa.AddLocalReference<jobject>(soa.Decode<Object*>(obj));
   }
 
   static void DeleteLocalRef(JNIEnv* env, jobject obj) {
diff --git a/runtime/mem_map.cc b/runtime/mem_map.cc
index 619b73c..9a34610 100644
--- a/runtime/mem_map.cc
+++ b/runtime/mem_map.cc
@@ -68,7 +68,9 @@
 #endif
 
 MemMap* MemMap::MapAnonymous(const char* name, byte* addr, size_t byte_count, int prot) {
-  CHECK_NE(0U, byte_count);
+  if (byte_count == 0) {
+    return new MemMap(name, NULL, 0, NULL, 0, prot);
+  }
   size_t page_aligned_byte_count = RoundUp(byte_count, kPageSize);
   CheckMapRequest(addr, page_aligned_byte_count);
 
@@ -102,9 +104,11 @@
 
 MemMap* MemMap::MapFileAtAddress(byte* addr, size_t byte_count,
                                  int prot, int flags, int fd, off_t start, bool reuse) {
-  CHECK_NE(0U, byte_count);
   CHECK_NE(0, prot);
   CHECK_NE(0, flags & (MAP_SHARED | MAP_PRIVATE));
+  if (byte_count == 0) {
+    return new MemMap("file", NULL, 0, NULL, 0, prot);
+  }
   // Adjust 'offset' to be page-aligned as required by mmap.
   int page_offset = start % kPageSize;
   off_t page_aligned_offset = start - page_offset;
@@ -153,10 +157,15 @@
                size_t base_size, int prot)
     : name_(name), begin_(begin), size_(size), base_begin_(base_begin), base_size_(base_size),
       prot_(prot) {
-  CHECK(begin_ != NULL);
-  CHECK_NE(size_, 0U);
-  CHECK(base_begin_ != NULL);
-  CHECK_NE(base_size_, 0U);
+  if (size_ == 0) {
+    CHECK(begin_ == NULL);
+    CHECK(base_begin_ == NULL);
+    CHECK_EQ(base_size_, 0U);
+  } else {
+    CHECK(begin_ != NULL);
+    CHECK(base_begin_ != NULL);
+    CHECK_NE(base_size_, 0U);
+  }
 };
 
 void MemMap::UnMapAtEnd(byte* new_end) {
diff --git a/runtime/mem_map_test.cc b/runtime/mem_map_test.cc
new file mode 100644
index 0000000..dade01b
--- /dev/null
+++ b/runtime/mem_map_test.cc
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2013 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 "mem_map.h"
+
+#include "UniquePtr.h"
+#include "gtest/gtest.h"
+
+namespace art {
+
+class MemMapTest : public testing::Test {};
+
+TEST_F(MemMapTest, MapAnonymousEmpty) {
+  UniquePtr<MemMap> map(MemMap::MapAnonymous("MapAnonymousEmpty",
+                                             NULL,
+                                             0,
+                                             PROT_READ));
+  ASSERT_TRUE(map.get() != NULL);
+}
+
+}  // namespace art
diff --git a/runtime/mirror/abstract_method.cc b/runtime/mirror/abstract_method.cc
index 58ef5f7..d08708f 100644
--- a/runtime/mirror/abstract_method.cc
+++ b/runtime/mirror/abstract_method.cc
@@ -20,6 +20,7 @@
 #include "base/stringpiece.h"
 #include "class-inl.h"
 #include "dex_file-inl.h"
+#include "dex_instruction.h"
 #include "gc/accounting/card_table-inl.h"
 #include "interpreter/interpreter.h"
 #include "jni_internal.h"
@@ -225,7 +226,8 @@
   return 0;
 }
 
-uint32_t AbstractMethod::FindCatchBlock(Class* exception_type, uint32_t dex_pc) const {
+uint32_t AbstractMethod::FindCatchBlock(Class* exception_type, uint32_t dex_pc,
+                                        bool* has_no_move_exception) const {
   MethodHelper mh(this);
   const DexFile::CodeItem* code_item = mh.GetCodeItem();
   // Iterate over the catch handlers associated with dex_pc
@@ -242,7 +244,11 @@
       LOG(WARNING) << "Unresolved exception class when finding catch block: "
           << mh.GetTypeDescriptorFromTypeIdx(iter_type_idx);
     } else if (iter_exception_type->IsAssignableFrom(exception_type)) {
-      return it.GetHandlerAddress();
+      uint32_t found_dex_pc = it.GetHandlerAddress();
+      const Instruction* first_catch_instr =
+          Instruction::At(&mh.GetCodeItem()->insns_[found_dex_pc]);
+      *has_no_move_exception = (first_catch_instr->Opcode() != Instruction::MOVE_EXCEPTION);
+      return found_dex_pc;
     }
   }
   // Handler not found
diff --git a/runtime/mirror/abstract_method.h b/runtime/mirror/abstract_method.h
index bbebece..2e6e262 100644
--- a/runtime/mirror/abstract_method.h
+++ b/runtime/mirror/abstract_method.h
@@ -407,8 +407,10 @@
   uintptr_t ToFirstNativeSafepointPc(const uint32_t dex_pc)
       const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  // Find the catch block for the given exception type and dex_pc
-  uint32_t FindCatchBlock(Class* exception_type, uint32_t dex_pc) const
+  // Find the catch block for the given exception type and dex_pc. When a catch block is found,
+  // indicates whether the found catch block is responsible for clearing the exception or whether
+  // a move-exception instruction is present.
+  uint32_t FindCatchBlock(Class* exception_type, uint32_t dex_pc, bool* has_no_move_exception) const
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   static void SetClasses(Class* java_lang_reflect_Constructor, Class* java_lang_reflect_Method);
diff --git a/runtime/runtime_support_llvm.cc b/runtime/runtime_support_llvm.cc
index 713bc40..93396d6 100644
--- a/runtime/runtime_support_llvm.cc
+++ b/runtime/runtime_support_llvm.cc
@@ -324,6 +324,12 @@
                                                                    current_method,
                                                                    catch_dex_pc,
                                                                    exception);
+    // If the catch block has no move-exception then clear the exception for it.
+    const Instruction* first_catch_instr =
+        Instruction::At(&mh.GetCodeItem()->insns_[catch_dex_pc]);
+    if (first_catch_instr->Opcode() != Instruction::MOVE_EXCEPTION) {
+      self->ClearException();
+    }
   }
   return result;
 }
diff --git a/runtime/scoped_thread_state_change.h b/runtime/scoped_thread_state_change.h
index 853d684..965e6b8 100644
--- a/runtime/scoped_thread_state_change.h
+++ b/runtime/scoped_thread_state_change.h
@@ -154,16 +154,11 @@
   /*
    * Add a local reference for an object to the indirect reference table associated with the
    * current stack frame.  When the native function returns, the reference will be discarded.
-   * Part of the ScopedJniThreadState as native code shouldn't be working on raw Object* without
-   * having transitioned its state.
    *
-   * We need to allow the same reference to be added multiple times.
+   * We need to allow the same reference to be added multiple times, and cope with NULL.
    *
-   * This will be called on otherwise unreferenced objects.  We cannot do GC allocations here, and
+   * This will be called on otherwise unreferenced objects. We cannot do GC allocations here, and
    * it's best if we don't grab a mutex.
-   *
-   * Returns the local reference (currently just the same pointer that was
-   * passed in), or NULL on failure.
    */
   template<typename T>
   T AddLocalReference(mirror::Object* obj) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
diff --git a/runtime/thread.cc b/runtime/thread.cc
index ea12c2e..d5fdd20 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -1709,7 +1709,7 @@
         self_(self), exception_(exception), is_deoptimization_(is_deoptimization),
         to_find_(is_deoptimization ? NULL : exception->GetClass()), throw_location_(throw_location),
         handler_quick_frame_(NULL), handler_quick_frame_pc_(0), handler_dex_pc_(0),
-        native_method_count_(0),
+        native_method_count_(0), clear_exception_(false),
         method_tracing_active_(is_deoptimization ||
                                Runtime::Current()->GetInstrumentation()->AreExitStubsInstalled()),
         instrumentation_frames_to_pop_(0), top_shadow_frame_(NULL), prev_shadow_frame_(NULL) {
@@ -1754,7 +1754,7 @@
       dex_pc = GetDexPc();
     }
     if (dex_pc != DexFile::kDexNoIndex) {
-      uint32_t found_dex_pc = method->FindCatchBlock(to_find_, dex_pc);
+      uint32_t found_dex_pc = method->FindCatchBlock(to_find_, dex_pc, &clear_exception_);
       if (found_dex_pc != DexFile::kDexNoIndex) {
         handler_dex_pc_ = found_dex_pc;
         handler_quick_frame_pc_ = method->ToNativePc(found_dex_pc);
@@ -1820,8 +1820,13 @@
         LOG(INFO) << "Handler: " << PrettyMethod(catch_method) << " (line: " << line_number << ")";
       }
     }
-    // Put exception back in root set and clear throw location.
-    self_->SetException(ThrowLocation(), exception_);
+    if (clear_exception_) {
+      // Exception was cleared as part of delivery.
+      DCHECK(!self_->IsExceptionPending());
+    } else {
+      // Put exception back in root set with clear throw location.
+      self_->SetException(ThrowLocation(), exception_);
+    }
     self_->EndAssertNoThreadSuspension(last_no_assert_suspension_cause_);
     // Do instrumentation events after allowing thread suspension again.
     instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
@@ -1864,6 +1869,8 @@
   uint32_t handler_dex_pc_;
   // Number of native methods passed in crawl (equates to number of SIRTs to pop)
   uint32_t native_method_count_;
+  // Should the exception be cleared as the catch block has no move-exception?
+  bool clear_exception_;
   // Is method tracing active?
   const bool method_tracing_active_;
   // Support for nesting no thread suspension checks.
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 1481ad9..9f0d911 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -555,12 +555,6 @@
             << "exception handler starts at bad address (" << dex_pc << ")";
         return false;
       }
-      const Instruction* inst = Instruction::At(code_item_->insns_ + dex_pc);
-      if (inst->Opcode() != Instruction::MOVE_EXCEPTION) {
-        Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "exception handler doesn't start with move-exception ("
-                                          << dex_pc << ")";
-        return false;
-      }
       insn_flags_[dex_pc].SetBranchTarget();
       // Ensure exception types are resolved so that they don't need resolution to be delivered,
       // unresolved exception types will be ignored by exception delivery
diff --git a/runtime/zip_archive.cc b/runtime/zip_archive.cc
index 2a48dc6..fc26f0f 100644
--- a/runtime/zip_archive.cc
+++ b/runtime/zip_archive.cc
@@ -259,6 +259,10 @@
 }
 
 bool ZipEntry::ExtractToMemory(uint8_t* begin, size_t size) {
+  // If size is zero, data offset will be meaningless, so bail out early.
+  if (size == 0) {
+    return true;
+  }
   off_t data_offset = GetDataOffset();
   if (data_offset == -1) {
     LOG(WARNING) << "Zip: data_offset=" << data_offset;