Merge "Do not replace a live phi with a dead phi." into mnc-dev
diff --git a/compiler/optimizing/graph_checker.cc b/compiler/optimizing/graph_checker.cc
index fd28f0b..44c4101 100644
--- a/compiler/optimizing/graph_checker.cc
+++ b/compiler/optimizing/graph_checker.cc
@@ -253,6 +253,30 @@
   }
 }
 
+void GraphChecker::VisitCheckCast(HCheckCast* check) {
+  VisitInstruction(check);
+  HInstruction* input = check->InputAt(1);
+  if (!input->IsLoadClass()) {
+    AddError(StringPrintf("%s:%d expects a HLoadClass as second input, not %s:%d.",
+                          check->DebugName(),
+                          check->GetId(),
+                          input->DebugName(),
+                          input->GetId()));
+  }
+}
+
+void GraphChecker::VisitInstanceOf(HInstanceOf* instruction) {
+  VisitInstruction(instruction);
+  HInstruction* input = instruction->InputAt(1);
+  if (!input->IsLoadClass()) {
+    AddError(StringPrintf("%s:%d expects a HLoadClass as second input, not %s:%d.",
+                          instruction->DebugName(),
+                          instruction->GetId(),
+                          input->DebugName(),
+                          input->GetId()));
+  }
+}
+
 void SSAChecker::VisitBasicBlock(HBasicBlock* block) {
   super_type::VisitBasicBlock(block);
 
diff --git a/compiler/optimizing/graph_checker.h b/compiler/optimizing/graph_checker.h
index b4314da..9284bb7 100644
--- a/compiler/optimizing/graph_checker.h
+++ b/compiler/optimizing/graph_checker.h
@@ -48,6 +48,10 @@
   // Check that the HasBoundsChecks() flag is set for bounds checks.
   void VisitBoundsCheck(HBoundsCheck* check) OVERRIDE;
 
+  // Check that HCheckCast and HInstanceOf have HLoadClass as second input.
+  void VisitCheckCast(HCheckCast* check) OVERRIDE;
+  void VisitInstanceOf(HInstanceOf* check) OVERRIDE;
+
   // Was the last visit of the graph valid?
   bool IsValid() const {
     return errors_.empty();
diff --git a/compiler/optimizing/reference_type_propagation.cc b/compiler/optimizing/reference_type_propagation.cc
index e93e061..302366e 100644
--- a/compiler/optimizing/reference_type_propagation.cc
+++ b/compiler/optimizing/reference_type_propagation.cc
@@ -130,6 +130,15 @@
   HBoundType* bound_type = nullptr;
 
   HInstruction* obj = instanceOf->InputAt(0);
+  if (obj->GetReferenceTypeInfo().IsExact() && !obj->IsPhi()) {
+    // This method is being called while doing a fixed-point calculation
+    // over phis. Non-phis instruction whose type is already known do
+    // not need to be bound to another type.
+    // Not that this also prevents replacing `HLoadClass` with a `HBoundType`.
+    // `HCheckCast` and `HInstanceOf` expect a `HLoadClass` as a second
+    // input.
+    return;
+  }
   for (HUseIterator<HInstruction*> it(obj->GetUses()); !it.Done(); it.Advance()) {
     HInstruction* user = it.Current()->GetUser();
     if (instanceOfTrueBlock->Dominates(user->GetBlock())) {
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 7a23746..74d5c0c 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -1038,6 +1038,10 @@
   bool OpenFile() {
     bool create_file = !oat_unstripped_.empty();  // as opposed to using open file descriptor
     if (create_file) {
+      // We're supposed to create this file. If the file already exists, it may be in use currently.
+      // We must not change the content of that file, then. So unlink it first.
+      unlink(oat_unstripped_.c_str());
+
       oat_file_.reset(OS::CreateEmptyFile(oat_unstripped_.c_str()));
       if (oat_location_.empty()) {
         oat_location_ = oat_filename_;
diff --git a/runtime/arch/arm64/quick_entrypoints_arm64.S b/runtime/arch/arm64/quick_entrypoints_arm64.S
index f90a6b0..fce5f23 100644
--- a/runtime/arch/arm64/quick_entrypoints_arm64.S
+++ b/runtime/arch/arm64/quick_entrypoints_arm64.S
@@ -1239,6 +1239,7 @@
     lsr x0, x0, #7
     strb w3, [x3, x0]
     ret
+    .cfi_adjust_cfa_offset 32  // 4 restores after cbz for unwinding.
 .Lthrow_array_store_exception:
     ldp x0, x1, [sp]
     .cfi_restore x0
diff --git a/runtime/arch/x86/quick_entrypoints_x86.S b/runtime/arch/x86/quick_entrypoints_x86.S
index 17778e9..870a747 100644
--- a/runtime/arch/x86/quick_entrypoints_x86.S
+++ b/runtime/arch/x86/quick_entrypoints_x86.S
@@ -1168,9 +1168,9 @@
     CFI_ADJUST_CFA_OFFSET(8)
     pushl MIRROR_OBJECT_CLASS_OFFSET(%edx)  // pass arg2 - type of the value to be stored
     CFI_ADJUST_CFA_OFFSET(4)
-    PUSH ebx                     // pass arg1 - component type of the array
+    PUSH ebx                      // pass arg1 - component type of the array
     call SYMBOL(artIsAssignableFromCode)  // (Class* a, Class* b)
-    addl LITERAL(16), %esp       // pop arguments
+    addl LITERAL(16), %esp        // pop arguments
     CFI_ADJUST_CFA_OFFSET(-16)
     testl %eax, %eax
     jz   .Lthrow_array_store_exception
@@ -1182,6 +1182,7 @@
     shrl LITERAL(7), %eax
     movb %dl, (%edx, %eax)
     ret
+    CFI_ADJUST_CFA_OFFSET(12)     // 3 POP after the jz for unwinding.
 .Lthrow_array_store_exception:
     POP  edx
     POP  ecx
diff --git a/runtime/arch/x86_64/quick_entrypoints_x86_64.S b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
index 62eebd4..f11eb06 100644
--- a/runtime/arch/x86_64/quick_entrypoints_x86_64.S
+++ b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
@@ -1243,6 +1243,7 @@
     movb %dl, (%rdx, %rdi)                       // Note: this assumes that top 32b of %rdi are zero
 //  movb %dl, (%rdx, %rdi)
     ret
+    CFI_ADJUST_CFA_OFFSET(32 + 4 * 8)  // Reset unwind info so following code unwinds.
 .Lthrow_array_store_exception:
     RESTORE_FP_CALLEE_SAVE_FRAME
     // Restore arguments.
diff --git a/runtime/java_vm_ext.cc b/runtime/java_vm_ext.cc
index eb9c32d..f1deacf 100644
--- a/runtime/java_vm_ext.cc
+++ b/runtime/java_vm_ext.cc
@@ -132,6 +132,8 @@
   }
 
   void* FindSymbol(const std::string& symbol_name) {
+    CHECK(!NeedsNativeBridge());
+
     return dlsym(handle_, symbol_name.c_str());
   }
 
@@ -234,9 +236,6 @@
           fn = library->FindSymbol(jni_long_name);
         }
       }
-      if (fn == nullptr) {
-        fn = library->FindSymbol(jni_long_name);
-      }
       if (fn != nullptr) {
         VLOG(jni) << "[Found native code for " << PrettyMethod(m)
                   << " in \"" << library->GetPath() << "\"]";
diff --git a/test/519-bound-load-class/expected.txt b/test/519-bound-load-class/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/519-bound-load-class/expected.txt
diff --git a/test/519-bound-load-class/info.txt b/test/519-bound-load-class/info.txt
new file mode 100644
index 0000000..5763962
--- /dev/null
+++ b/test/519-bound-load-class/info.txt
@@ -0,0 +1,3 @@
+Regression test for the optimizing compiler that
+used to crash when a `HCheckCast` did not have a `HLoadClass`
+as second input.
diff --git a/test/519-bound-load-class/src/Main.java b/test/519-bound-load-class/src/Main.java
new file mode 100644
index 0000000..41bb951
--- /dev/null
+++ b/test/519-bound-load-class/src/Main.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+public class Main {
+  public static void main(String[] args) {
+    Object o = Main.class;
+    if (o instanceof Main) {
+      System.out.println((Main)o);
+    }
+  }
+}