Merge "MIPS: Initial version of optimizing compiler for MIPS64R6." into mnc-dev
diff --git a/build/Android.common_test.mk b/build/Android.common_test.mk
index f3e1cc3..45b6490 100644
--- a/build/Android.common_test.mk
+++ b/build/Android.common_test.mk
@@ -61,6 +61,9 @@
 # Do you want tracing tests run?
 ART_TEST_TRACE ?= $(ART_TEST_FULL)
 
+# Do you want tracing tests (streaming mode) run?
+ART_TEST_TRACE_STREAM ?= $(ART_TEST_FULL)
+
 # Do you want tests with GC verification enabled run?
 ART_TEST_GC_VERIFY ?= $(ART_TEST_FULL)
 
diff --git a/compiler/dex/type_inference.cc b/compiler/dex/type_inference.cc
index a0dfcbe..c93fe20 100644
--- a/compiler/dex/type_inference.cc
+++ b/compiler/dex/type_inference.cc
@@ -572,15 +572,21 @@
 
   if (type_conflict) {
     /*
-     * We don't normally expect to see a Dalvik register definition used both as a
-     * floating point and core value, though technically it could happen with constants.
-     * Until we have proper typing, detect this situation and disable register promotion
-     * (which relies on the distinction between core a fp usages).
+     * Each dalvik register definition should be used either as a reference, or an
+     * integer or a floating point value. We don't normally expect to see a Dalvik
+     * register definition used in two or three of these roles though technically it
+     * could happen with constants (0 for all three roles, non-zero for integer and
+     * FP). Detect this situation and disable optimizations that rely on correct
+     * typing, i.e. register promotion, GVN/LVN and GVN-based DCE.
      */
     LOG(WARNING) << PrettyMethod(cu_->method_idx, *cu_->dex_file)
                  << " has type conflict block for sreg " << conflict_s_reg
                  << ", disabling register promotion.";
-    cu_->disable_opt |= (1 << kPromoteRegs);
+    cu_->disable_opt |=
+        (1u << kPromoteRegs) |
+        (1u << kGlobalValueNumbering) |
+        (1u << kGvnDeadCodeElimination) |
+        (1u << kLocalValueNumbering);
   }
 }
 
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 75217c8..f1293b7 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -492,6 +492,16 @@
     instruction_set = kThumb2;
   }
 
+  // `run_optimizations_` is set explicitly (either through a compiler filter
+  // or the debuggable flag). If it is set, we can run baseline. Otherwise, we
+  // fall back to Quick.
+  bool should_use_baseline = !run_optimizations_;
+  bool can_optimize = CanOptimize(*code_item);
+  if (!can_optimize && !should_use_baseline) {
+    // We know we will not compile this method. Bail out before doing any work.
+    return nullptr;
+  }
+
   // Do not attempt to compile on architectures we do not support.
   if (!IsInstructionSetSupported(instruction_set)) {
     MaybeRecordStat(MethodCompilationStat::kNotCompiledUnsupportedIsa);
@@ -565,13 +575,8 @@
     }
   }
 
-  bool can_optimize = CanOptimize(*code_item);
   bool can_allocate_registers = RegisterAllocator::CanAllocateRegistersFor(*graph, instruction_set);
 
-  // `run_optimizations_` is set explicitly (either through a compiler filter
-  // or the debuggable flag). If it is set, we can run baseline. Otherwise, we fall back
-  // to Quick.
-  bool can_use_baseline = !run_optimizations_;
   if (run_optimizations_ && can_optimize && can_allocate_registers) {
     VLOG(compiler) << "Optimizing " << method_name;
 
@@ -594,7 +599,7 @@
   } else if (shouldOptimize && can_allocate_registers) {
     LOG(FATAL) << "Could not allocate registers in optimizing compiler";
     UNREACHABLE();
-  } else if (can_use_baseline) {
+  } else if (should_use_baseline) {
     VLOG(compiler) << "Compile baseline " << method_name;
 
     if (!run_optimizations_) {
diff --git a/runtime/base/mutex.h b/runtime/base/mutex.h
index aa91ca1..678d55b 100644
--- a/runtime/base/mutex.h
+++ b/runtime/base/mutex.h
@@ -80,6 +80,8 @@
   kMarkSweepMarkStackLock,
   kInternTableLock,
   kOatFileSecondaryLookupLock,
+  kTracingUniqueMethodsLock,
+  kTracingStreamingLock,
   kDefaultMutexLevel,
   kMarkSweepLargeObjectLock,
   kPinTableLock,
diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc
index 6ab4455..0a01f78 100644
--- a/runtime/jni_internal.cc
+++ b/runtime/jni_internal.cc
@@ -554,15 +554,16 @@
     return soa.AddLocalReference<jobject>(decoded_obj);
   }
 
-  static void DeleteLocalRef(JNIEnv* env, jobject obj)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  static void DeleteLocalRef(JNIEnv* env, jobject obj) {
     if (obj == nullptr) {
       return;
     }
-    IndirectReferenceTable& locals = reinterpret_cast<JNIEnvExt*>(env)->locals;
-
-    uint32_t cookie = reinterpret_cast<JNIEnvExt*>(env)->local_ref_cookie;
-    if (!locals.Remove(cookie, obj)) {
+    // SOA is only necessary to have exclusion between GC root marking and removing.
+    // We don't want to have the GC attempt to mark a null root if we just removed
+    // it. b/22119403
+    ScopedObjectAccess soa(env);
+    auto* ext_env = down_cast<JNIEnvExt*>(env);
+    if (!ext_env->locals.Remove(ext_env->local_ref_cookie, obj)) {
       // Attempting to delete a local reference that is not in the
       // topmost local reference frame is a no-op.  DeleteLocalRef returns
       // void and doesn't throw any exceptions, but we should probably
diff --git a/runtime/trace.cc b/runtime/trace.cc
index 5a43b56..487baed 100644
--- a/runtime/trace.cc
+++ b/runtime/trace.cc
@@ -427,7 +427,7 @@
       // Do not try to erase, so flush and close explicitly.
       if (flush_file) {
         if (the_trace->trace_file_->Flush() != 0) {
-          PLOG(ERROR) << "Could not flush trace file.";
+          PLOG(WARNING) << "Could not flush trace file.";
         }
       } else {
         the_trace->trace_file_->MarkUnchecked();  // Do not trigger guard.
@@ -581,7 +581,7 @@
       buffer_size_(std::max(kMinBufSize, buffer_size)),
       start_time_(MicroTime()), clock_overhead_ns_(GetClockOverheadNanoSeconds()), cur_offset_(0),
       overflow_(false), interval_us_(0), streaming_lock_(nullptr),
-      unique_methods_lock_(new Mutex("unique methods lock")) {
+      unique_methods_lock_(new Mutex("unique methods lock", kTracingUniqueMethodsLock)) {
   uint16_t trace_version = GetTraceVersion(clock_source_);
   if (output_mode == TraceOutputMode::kStreaming) {
     trace_version |= 0xF0U;
@@ -603,13 +603,14 @@
 
   if (output_mode == TraceOutputMode::kStreaming) {
     streaming_file_name_ = trace_name;
-    streaming_lock_ = new Mutex("tracing lock");
+    streaming_lock_ = new Mutex("tracing lock", LockLevel::kTracingStreamingLock);
     seen_threads_.reset(new ThreadIDBitSet());
   }
 }
 
 Trace::~Trace() {
   delete streaming_lock_;
+  delete unique_methods_lock_;
 }
 
 static uint64_t ReadBytes(uint8_t* buf, size_t bytes) {
@@ -634,13 +635,15 @@
 }
 
 static void GetVisitedMethodsFromBitSets(
-    const std::map<mirror::DexCache*, DexIndexBitSet*>& seen_methods,
+    const std::map<const DexFile*, DexIndexBitSet*>& seen_methods,
     std::set<ArtMethod*>* visited_methods) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   for (auto& e : seen_methods) {
     DexIndexBitSet* bit_set = e.second;
+    mirror::DexCache* dex_cache = class_linker->FindDexCache(*e.first);
     for (uint32_t i = 0; i < bit_set->size(); ++i) {
       if ((*bit_set)[i]) {
-        visited_methods->insert(e.first->GetResolvedMethod(i, sizeof(void*)));
+        visited_methods->insert(dex_cache->GetResolvedMethod(i, sizeof(void*)));
       }
     }
   }
@@ -819,15 +822,16 @@
 
 bool Trace::RegisterMethod(ArtMethod* method) {
   mirror::DexCache* dex_cache = method->GetDexCache();
+  const DexFile* dex_file = dex_cache->GetDexFile();
   auto* resolved_method = dex_cache->GetResolvedMethod(method->GetDexMethodIndex(), sizeof(void*));
   if (resolved_method != method) {
     DCHECK(resolved_method == nullptr);
     dex_cache->SetResolvedMethod(method->GetDexMethodIndex(), method, sizeof(void*));
   }
-  if (seen_methods_.find(dex_cache) == seen_methods_.end()) {
-    seen_methods_.insert(std::make_pair(dex_cache, new DexIndexBitSet()));
+  if (seen_methods_.find(dex_file) == seen_methods_.end()) {
+    seen_methods_.insert(std::make_pair(dex_file, new DexIndexBitSet()));
   }
-  DexIndexBitSet* bit_set = seen_methods_.find(dex_cache)->second;
+  DexIndexBitSet* bit_set = seen_methods_.find(dex_file)->second;
   if (!(*bit_set)[method->GetDexMethodIndex()]) {
     bit_set->set(method->GetDexMethodIndex());
     return true;
diff --git a/runtime/trace.h b/runtime/trace.h
index 7bc495a..69e6acc 100644
--- a/runtime/trace.h
+++ b/runtime/trace.h
@@ -35,12 +35,9 @@
 
 namespace art {
 
-namespace mirror {
-  class DexCache;
-}  // namespace mirror
-
 class ArtField;
 class ArtMethod;
+class DexFile;
 class Thread;
 
 using DexIndexBitSet = std::bitset<65536>;
@@ -126,15 +123,18 @@
 
   // Stop tracing. This will finish the trace and write it to file/send it via DDMS.
   static void Stop()
-        LOCKS_EXCLUDED(Locks::mutator_lock_,
-                       Locks::thread_list_lock_,
-                       Locks::trace_lock_);
+      LOCKS_EXCLUDED(Locks::mutator_lock_,
+                     Locks::thread_list_lock_,
+                     Locks::trace_lock_);
   // Abort tracing. This will just stop tracing and *not* write/send the collected data.
   static void Abort()
       LOCKS_EXCLUDED(Locks::mutator_lock_,
                      Locks::thread_list_lock_,
                      Locks::trace_lock_);
-  static void Shutdown() LOCKS_EXCLUDED(Locks::trace_lock_);
+  static void Shutdown()
+      LOCKS_EXCLUDED(Locks::mutator_lock_,
+                     Locks::thread_list_lock_,
+                     Locks::trace_lock_);
   static TracingMode GetMethodTracingMode() LOCKS_EXCLUDED(Locks::trace_lock_);
 
   bool UseWallClock();
@@ -188,7 +188,10 @@
   // The sampling interval in microseconds is passed as an argument.
   static void* RunSamplingThread(void* arg) LOCKS_EXCLUDED(Locks::trace_lock_);
 
-  static void StopTracing(bool finish_tracing, bool flush_file);
+  static void StopTracing(bool finish_tracing, bool flush_file)
+      LOCKS_EXCLUDED(Locks::mutator_lock_,
+                     Locks::thread_list_lock_,
+                     Locks::trace_lock_);
   void FinishTracing() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   void ReadClocks(Thread* thread, uint32_t* thread_clock_diff, uint32_t* wall_clock_diff);
@@ -279,12 +282,12 @@
   // Streaming mode data.
   std::string streaming_file_name_;
   Mutex* streaming_lock_;
-  std::map<mirror::DexCache*, DexIndexBitSet*> seen_methods_;
+  std::map<const DexFile*, DexIndexBitSet*> seen_methods_;
   std::unique_ptr<ThreadIDBitSet> seen_threads_;
 
   // Bijective map from ArtMethod* to index.
   // Map from ArtMethod* to index in unique_methods_;
-  Mutex* unique_methods_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
+  Mutex* unique_methods_lock_ ACQUIRED_AFTER(streaming_lock_);
   std::unordered_map<ArtMethod*, uint32_t> art_method_id_map_ GUARDED_BY(unique_methods_lock_);
   std::vector<ArtMethod*> unique_methods_ GUARDED_BY(unique_methods_lock_);
 
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 1f7dd58..085f741 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -385,7 +385,7 @@
                                bool allow_thread_suspension)
     : self_(self),
       reg_types_(can_load_classes),
-      work_insn_idx_(-1),
+      work_insn_idx_(DexFile::kDexNoIndex),
       dex_method_idx_(dex_method_idx),
       mirror_method_(method),
       method_access_flags_(method_access_flags),
@@ -409,7 +409,8 @@
       has_check_casts_(false),
       has_virtual_or_interface_invokes_(false),
       verify_to_dump_(verify_to_dump),
-      allow_thread_suspension_(allow_thread_suspension) {
+      allow_thread_suspension_(allow_thread_suspension),
+      link_(nullptr) {
   self->PushVerifier(this);
   DCHECK(class_def != nullptr);
 }
@@ -599,12 +600,16 @@
         // We need to save the work_line if the instruction wasn't throwing before. Otherwise we'll
         // try to merge garbage.
         // Note: this assumes that Fail is called before we do any work_line modifications.
-        const uint16_t* insns = code_item_->insns_ + work_insn_idx_;
-        const Instruction* inst = Instruction::At(insns);
-        int opcode_flags = Instruction::FlagsOf(inst->Opcode());
+        // Note: this can fail before we touch any instruction, for the signature of a method. So
+        //       add a check.
+        if (work_insn_idx_ < DexFile::kDexNoIndex) {
+          const uint16_t* insns = code_item_->insns_ + work_insn_idx_;
+          const Instruction* inst = Instruction::At(insns);
+          int opcode_flags = Instruction::FlagsOf(inst->Opcode());
 
-        if ((opcode_flags & Instruction::kThrow) == 0 && CurrentInsnFlags()->IsInTry()) {
-          saved_line_->CopyFromLine(work_line_.get());
+          if ((opcode_flags & Instruction::kThrow) == 0 && CurrentInsnFlags()->IsInTry()) {
+            saved_line_->CopyFromLine(work_line_.get());
+          }
         }
       }
       break;
@@ -1236,6 +1241,9 @@
     PrependToLastFailMessage(prepend);
     return false;
   }
+  // We may have a runtime failure here, clear.
+  have_pending_runtime_throw_failure_ = false;
+
   /* Perform code flow verification. */
   if (!CodeFlowVerifyMethod()) {
     DCHECK_NE(failures_.size(), 0U);
diff --git a/test/800-smali/expected.txt b/test/800-smali/expected.txt
index 80b4f57..2196a88 100644
--- a/test/800-smali/expected.txt
+++ b/test/800-smali/expected.txt
@@ -22,4 +22,5 @@
 b/21863767
 b/21886894
 b/22080519
+b/21645819
 Done!
diff --git a/test/800-smali/smali/b_21645819.smali b/test/800-smali/smali/b_21645819.smali
new file mode 100644
index 0000000..195d662
--- /dev/null
+++ b/test/800-smali/smali/b_21645819.smali
@@ -0,0 +1,9 @@
+.class public LB21645819;
+.super Ljava/lang/Object;
+
+# The method declares a parameter of an inaccessible class. This should not abort/kill us.
+
+.method public static run(Lpkg/ProtectedClass;)V
+.registers 10
+       return-void
+.end method
\ No newline at end of file
diff --git a/test/800-smali/src/Main.java b/test/800-smali/src/Main.java
index 337d0d9..e6f065e 100644
--- a/test/800-smali/src/Main.java
+++ b/test/800-smali/src/Main.java
@@ -91,6 +91,8 @@
                 null));
         testCases.add(new TestCase("b/22080519", "B22080519", "run", null,
                 new NullPointerException(), null));
+        testCases.add(new TestCase("b/21645819", "B21645819", "run", new Object[] { null },
+                null, null));
     }
 
     public void runTests() {
diff --git a/test/800-smali/src/pkg/ProtectedClass.java b/test/800-smali/src/pkg/ProtectedClass.java
new file mode 100644
index 0000000..b262155
--- /dev/null
+++ b/test/800-smali/src/pkg/ProtectedClass.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+package pkg;
+
+class ProtectedClass {
+}
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index c19133c..89ed4c5 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -101,6 +101,9 @@
 ifeq ($(ART_TEST_TRACE),true)
   TRACE_TYPES += trace
 endif
+ifeq ($(ART_TEST_TRACE_STREAM),true)
+  TRACE_TYPES += stream
+endif
 GC_TYPES := cms
 ifeq ($(ART_TEST_GC_STRESS),true)
   GC_TYPES += gcstress
@@ -310,9 +313,9 @@
   137-cfi \
   802-deoptimization
 
-ifneq (,$(filter trace,$(TRACE_TYPES)))
+ifneq (,$(filter trace stream,$(TRACE_TYPES)))
   ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),$(PREBUILD_TYPES), \
-      $(COMPILER_TYPES),$(RELOCATE_TYPES),trace,$(GC_TYPES),$(JNI_TYPES),$(IMAGE_TYPES), \
+      $(COMPILER_TYPES),$(RELOCATE_TYPES),trace stream,$(GC_TYPES),$(JNI_TYPES),$(IMAGE_TYPES), \
       $(PICTEST_TYPES),$(DEBUGGABLE_TYPES), $(TEST_ART_BROKEN_TRACING_RUN_TESTS),$(ALL_ADDRESS_SIZES))
 endif
 
@@ -692,7 +695,13 @@
     ifeq ($(6),ntrace)
       test_groups += ART_RUN_TEST_$$(uc_host_or_target)_NO_TRACE_RULES
     else
-      $$(error found $(6) expected $(TRACE_TYPES))
+      ifeq ($(6),stream)
+        # Group streaming under normal tracing rules.
+        test_groups += ART_RUN_TEST_$$(uc_host_or_target)_TRACE_RULES
+        run_test_options += --trace --stream
+      else
+        $$(error found $(6) expected $(TRACE_TYPES))
+      endif
     endif
   endif
   ifeq ($(7),gcverify)
diff --git a/test/run-test b/test/run-test
index dc60eda..3f17861 100755
--- a/test/run-test
+++ b/test/run-test
@@ -92,6 +92,7 @@
 build_only="no"
 suffix64=""
 trace="false"
+trace_stream="false"
 basic_verify="false"
 gc_verify="false"
 gc_stress="false"
@@ -267,6 +268,9 @@
     elif [ "x$1" = "x--trace" ]; then
         trace="true"
         shift
+    elif [ "x$1" = "x--stream" ]; then
+        trace_stream="true"
+        shift
     elif [ "x$1" = "x--always-clean" ]; then
         always_clean="yes"
         shift
@@ -303,7 +307,19 @@
   run_args="${run_args} --runtime-option -Xgc:SS --runtime-option -Xms2m --runtime-option -Xmx2m"
 fi
 if [ "$trace" = "true" ]; then
-    run_args="${run_args} --runtime-option -Xmethod-trace --runtime-option -Xmethod-trace-file:${DEX_LOCATION}/trace.bin --runtime-option -Xmethod-trace-file-size:2000000"
+    run_args="${run_args} --runtime-option -Xmethod-trace --runtime-option -Xmethod-trace-file-size:2000000"
+    if [ "$trace_stream" = "true" ]; then
+        # Streaming mode uses the file size as the buffer size. So output gets really large. Drop
+        # the ability to analyze the file and just write to /dev/null.
+        run_args="${run_args} --runtime-option -Xmethod-trace-file:/dev/null"
+        # Enable streaming mode.
+        run_args="${run_args} --runtime-option -Xmethod-trace-stream"
+    else
+        run_args="${run_args} --runtime-option -Xmethod-trace-file:${DEX_LOCATION}/trace.bin"
+    fi
+elif [ "$trace_stream" = "true" ]; then
+    echo "Cannot use --stream without --trace."
+    exit 1
 fi
 
 # Most interesting target architecture variables are Makefile variables, not environment variables.
@@ -469,6 +485,7 @@
              "files."
         echo "    --64                  Run the test in 64-bit mode"
         echo "    --trace               Run with method tracing"
+        echo "    --stream              Run method tracing in streaming mode (requires --trace)"
         echo "    --gcstress            Run with gc stress testing"
         echo "    --gcverify            Run with gc verification"
         echo "    --always-clean        Delete the test files even if the test fails."