Merge "Fix darwin run-test problems"
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 1e64c00..9c2cc6c 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -2093,7 +2093,6 @@
     // The boot class loader, search the boot class path.
     ClassPathEntry pair = FindInClassPath(descriptor, boot_class_path_);
     if (pair.second != nullptr) {
-      StackHandleScope<1> hs(self);
       return DefineClass(descriptor, NullHandle<mirror::ClassLoader>(), *pair.first, *pair.second);
     } else {
       // The boot class loader is searched ahead of the application class loader, failures are
@@ -2132,6 +2131,87 @@
     }
   } else {
     ScopedObjectAccessUnchecked soa(self);
+    if (class_loader->GetClass() ==
+            soa.Decode<mirror::Class*>(WellKnownClasses::dalvik_system_PathClassLoader) &&
+        class_loader->GetParent()->GetClass() ==
+            soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_BootClassLoader)) {
+      ClassPathEntry pair = FindInClassPath(descriptor, boot_class_path_);
+      // Check if this would be found in the parent boot class loader.
+      if (pair.second != nullptr) {
+        mirror::Class* klass = LookupClass(descriptor, nullptr);
+        if (klass != nullptr) {
+          return klass;
+        }
+        klass = DefineClass(descriptor, NullHandle<mirror::ClassLoader>(), *pair.first,
+                            *pair.second);
+        if (klass == nullptr) {
+          CHECK(self->IsExceptionPending()) << descriptor;
+          self->ClearException();
+        } else {
+          return klass;
+        }
+      } else {
+        // RegisterDexFile may allocate dex caches (and cause thread suspension).
+        StackHandleScope<3> hs(self);
+        // The class loader is a PathClassLoader which inherits from BaseDexClassLoader.
+        // We need to get the DexPathList and loop through it.
+        Handle<mirror::ArtField> cookie_field =
+            hs.NewHandle(soa.DecodeField(WellKnownClasses::dalvik_system_DexFile_cookie));
+        Handle<mirror::ArtField> dex_file_field =
+            hs.NewHandle(
+                soa.DecodeField(WellKnownClasses::dalvik_system_DexPathList$Element_dexFile));
+        mirror::Object* dex_path_list =
+            soa.DecodeField(WellKnownClasses::dalvik_system_PathClassLoader_pathList)->
+            GetObject(class_loader.Get());
+        if (dex_path_list != nullptr && dex_file_field.Get() != nullptr &&
+            cookie_field.Get() != nullptr) {
+          // DexPathList has an array dexElements of Elements[] which each contain a dex file.
+          mirror::Object* dex_elements_obj =
+              soa.DecodeField(WellKnownClasses::dalvik_system_DexPathList_dexElements)->
+              GetObject(dex_path_list);
+          // Loop through each dalvik.system.DexPathList$Element's dalvik.system.DexFile and look
+          // at the mCookie which is a DexFile vector.
+          if (dex_elements_obj != nullptr) {
+            Handle<mirror::ObjectArray<mirror::Object>> dex_elements =
+                hs.NewHandle(dex_elements_obj->AsObjectArray<mirror::Object>());
+            for (int32_t i = 0; i < dex_elements->GetLength(); ++i) {
+              mirror::Object* element = dex_elements->GetWithoutChecks(i);
+              if (element == nullptr) {
+                // Should never happen, fall back to java code to throw a NPE.
+                break;
+              }
+              mirror::Object* dex_file = dex_file_field->GetObject(element);
+              if (dex_file != nullptr) {
+                const uint64_t cookie = cookie_field->GetLong(dex_file);
+                auto* dex_files =
+                    reinterpret_cast<std::vector<const DexFile*>*>(static_cast<uintptr_t>(cookie));
+                if (dex_files == nullptr) {
+                  // This should never happen so log a warning.
+                  LOG(WARNING) << "Null DexFile::mCookie for " << descriptor;
+                  break;
+                }
+                for (const DexFile* dex_file : *dex_files) {
+                  const DexFile::ClassDef* dex_class_def = dex_file->FindClassDef(descriptor);
+                  if (dex_class_def != nullptr) {
+                    RegisterDexFile(*dex_file);
+                    mirror::Class* klass =
+                        DefineClass(descriptor, class_loader, *dex_file, *dex_class_def);
+                    if (klass == nullptr) {
+                      CHECK(self->IsExceptionPending()) << descriptor;
+                      self->ClearException();
+                      // Exit the loop to make the java code generate an exception.
+                      i = dex_elements->GetLength();
+                      break;
+                    }
+                    return klass;
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
     ScopedLocalRef<jobject> class_loader_object(soa.Env(),
                                                 soa.AddLocalReference<jobject>(class_loader.Get()));
     std::string class_name_string(DescriptorToDot(descriptor));
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 494781a..2048160 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -120,7 +120,7 @@
       desired_collector_type_(foreground_collector_type_),
       heap_trim_request_lock_(nullptr),
       last_trim_time_(0),
-      last_heap_transition_time_(0),
+      heap_transition_or_trim_target_time_(0),
       heap_trim_request_pending_(false),
       parallel_gc_threads_(parallel_gc_threads),
       conc_gc_threads_(conc_gc_threads),
@@ -916,6 +916,35 @@
 }
 
 void Heap::DoPendingTransitionOrTrim() {
+  Thread* self = Thread::Current();
+  CollectorType desired_collector_type;
+  // Wait until we reach the desired transition time.
+  while (true) {
+    uint64_t wait_time;
+    {
+      MutexLock mu(self, *heap_trim_request_lock_);
+      desired_collector_type = desired_collector_type_;
+      uint64_t current_time = NanoTime();
+      if (current_time >= heap_transition_or_trim_target_time_) {
+        break;
+      }
+      wait_time = heap_transition_or_trim_target_time_ - current_time;
+    }
+    ScopedThreadStateChange tsc(self, kSleeping);
+    usleep(wait_time / 1000);  // Usleep takes microseconds.
+  }
+  // Launch homogeneous space compaction if it is desired.
+  if (desired_collector_type == kCollectorTypeHomogeneousSpaceCompact) {
+    if (!CareAboutPauseTimes()) {
+      PerformHomogeneousSpaceCompact();
+    }
+    // No need to Trim(). Homogeneous space compaction may free more virtual and physical memory.
+    desired_collector_type = collector_type_;
+    return;
+  }
+  // Transition the collector if the desired collector type is not the same as the current
+  // collector type.
+  TransitionCollector(desired_collector_type);
   if (!CareAboutPauseTimes()) {
     // Deflate the monitors, this can cause a pause but shouldn't matter since we don't care
     // about pauses.
@@ -927,23 +956,7 @@
         << PrettyDuration(NanoTime() - start_time);
     runtime->GetThreadList()->ResumeAll();
   }
-  if (NanoTime() - last_heap_transition_time_ > kCollectorTransitionWait) {
-    // Launch homogeneous space compaction if it is desired.
-    if (desired_collector_type_ == kCollectorTypeHomogeneousSpaceCompact) {
-      if (!CareAboutPauseTimes()) {
-        PerformHomogeneousSpaceCompact();
-        last_heap_transition_time_ = NanoTime();
-      }
-      desired_collector_type_ = collector_type_;
-    } else {
-      // Transition the collector if the desired collector type is not the same as the current
-      // collector type.
-      TransitionCollector(desired_collector_type_);
-      last_heap_transition_time_ = NanoTime();
-    }
-  }
-  // Do a heap trim if it is needed. This is good to do even with hspace compaction since it may
-  // trim the native heap and dlmalloc spaces.
+  // Do a heap trim if it is needed.
   Trim();
 }
 
@@ -2977,6 +2990,8 @@
     if (desired_collector_type_ == desired_collector_type) {
       return;
     }
+    heap_transition_or_trim_target_time_ =
+        std::max(heap_transition_or_trim_target_time_, NanoTime() + delta_time);
     desired_collector_type_ = desired_collector_type;
   }
   SignalHeapTrimDaemon(self);
@@ -2998,7 +3013,10 @@
 
   Thread* self = Thread::Current();
   Runtime* runtime = Runtime::Current();
-  if (runtime == nullptr || !runtime->IsFinishedStarting() || runtime->IsShuttingDown(self)) {
+  if (runtime == nullptr || !runtime->IsFinishedStarting() || runtime->IsShuttingDown(self) ||
+      runtime->IsZygote()) {
+    // Ignore the request if we are the zygote to prevent app launching lag due to sleep in heap
+    // trimmer daemon. b/17310019
     // Heap trimming isn't supported without a Java runtime or Daemons (such as at dex2oat time)
     // Also: we do not wish to start a heap trim if the runtime is shutting down (a racy check
     // as we don't hold the lock while requesting the trim).
@@ -3012,6 +3030,10 @@
       return;
     }
     heap_trim_request_pending_ = true;
+    uint64_t current_time = NanoTime();
+    if (heap_transition_or_trim_target_time_ < current_time) {
+      heap_transition_or_trim_target_time_ = current_time + kHeapTrimWait;
+    }
   }
   // Notify the daemon thread which will actually do the heap trim.
   SignalHeapTrimDaemon(self);
@@ -3064,8 +3086,6 @@
   }
   env->CallStaticVoidMethod(WellKnownClasses::java_lang_System,
                             WellKnownClasses::java_lang_System_runFinalization);
-  env->CallStaticVoidMethod(WellKnownClasses::java_lang_System,
-                            WellKnownClasses::java_lang_System_runFinalization);
 }
 
 void Heap::RegisterNativeAllocation(JNIEnv* env, size_t bytes) {
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index 3bfa748..9742277 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -830,8 +830,8 @@
   Mutex* heap_trim_request_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
   // When we want to perform the next heap trim (nano seconds).
   uint64_t last_trim_time_ GUARDED_BY(heap_trim_request_lock_);
-  // When we last performed a heap transition or hspace compact.
-  uint64_t last_heap_transition_time_;
+  // When we want to perform the next heap transition (nano seconds) or heap trim.
+  uint64_t heap_transition_or_trim_target_time_ GUARDED_BY(heap_trim_request_lock_);
   // If we have a heap trim request pending.
   bool heap_trim_request_pending_ GUARDED_BY(heap_trim_request_lock_);
 
diff --git a/runtime/mirror/class_loader.h b/runtime/mirror/class_loader.h
index f3594e4..ff2ad89 100644
--- a/runtime/mirror/class_loader.h
+++ b/runtime/mirror/class_loader.h
@@ -32,6 +32,9 @@
   static constexpr uint32_t InstanceSize() {
     return sizeof(ClassLoader);
   }
+  ClassLoader* GetParent() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    return GetFieldObject<ClassLoader>(OFFSET_OF_OBJECT_MEMBER(ClassLoader, parent_));
+  }
 
  private:
   // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc
index 3a6a72b..7068a4d 100644
--- a/runtime/well_known_classes.cc
+++ b/runtime/well_known_classes.cc
@@ -26,7 +26,11 @@
 namespace art {
 
 jclass WellKnownClasses::com_android_dex_Dex;
+jclass WellKnownClasses::dalvik_system_DexFile;
+jclass WellKnownClasses::dalvik_system_DexPathList;
+jclass WellKnownClasses::dalvik_system_DexPathList$Element;
 jclass WellKnownClasses::dalvik_system_PathClassLoader;
+jclass WellKnownClasses::java_lang_BootClassLoader;
 jclass WellKnownClasses::java_lang_ClassLoader;
 jclass WellKnownClasses::java_lang_ClassNotFoundException;
 jclass WellKnownClasses::java_lang_Daemons;
@@ -79,6 +83,10 @@
 jmethodID WellKnownClasses::org_apache_harmony_dalvik_ddmc_DdmServer_broadcast;
 jmethodID WellKnownClasses::org_apache_harmony_dalvik_ddmc_DdmServer_dispatch;
 
+jfieldID WellKnownClasses::dalvik_system_DexFile_cookie;
+jfieldID WellKnownClasses::dalvik_system_PathClassLoader_pathList;
+jfieldID WellKnownClasses::dalvik_system_DexPathList_dexElements;
+jfieldID WellKnownClasses::dalvik_system_DexPathList$Element_dexFile;
 jfieldID WellKnownClasses::java_lang_Thread_daemon;
 jfieldID WellKnownClasses::java_lang_Thread_group;
 jfieldID WellKnownClasses::java_lang_Thread_lock;
@@ -131,7 +139,11 @@
 
 void WellKnownClasses::Init(JNIEnv* env) {
   com_android_dex_Dex = CacheClass(env, "com/android/dex/Dex");
+  dalvik_system_DexFile = CacheClass(env, "dalvik/system/DexFile");
+  dalvik_system_DexPathList = CacheClass(env, "dalvik/system/DexPathList");
+  dalvik_system_DexPathList$Element = CacheClass(env, "dalvik/system/DexPathList$Element");
   dalvik_system_PathClassLoader = CacheClass(env, "dalvik/system/PathClassLoader");
+  java_lang_BootClassLoader = CacheClass(env, "java/lang/BootClassLoader");
   java_lang_ClassLoader = CacheClass(env, "java/lang/ClassLoader");
   java_lang_ClassNotFoundException = CacheClass(env, "java/lang/ClassNotFoundException");
   java_lang_Daemons = CacheClass(env, "java/lang/Daemons");
@@ -179,6 +191,10 @@
   org_apache_harmony_dalvik_ddmc_DdmServer_broadcast = CacheMethod(env, org_apache_harmony_dalvik_ddmc_DdmServer, true, "broadcast", "(I)V");
   org_apache_harmony_dalvik_ddmc_DdmServer_dispatch = CacheMethod(env, org_apache_harmony_dalvik_ddmc_DdmServer, true, "dispatch", "(I[BII)Lorg/apache/harmony/dalvik/ddmc/Chunk;");
 
+  dalvik_system_DexFile_cookie = CacheField(env, dalvik_system_DexFile, false, "mCookie", "J");
+  dalvik_system_PathClassLoader_pathList = CacheField(env, dalvik_system_PathClassLoader, false, "pathList", "Ldalvik/system/DexPathList;");
+  dalvik_system_DexPathList_dexElements = CacheField(env, dalvik_system_DexPathList, false, "dexElements", "[Ldalvik/system/DexPathList$Element;");
+  dalvik_system_DexPathList$Element_dexFile = CacheField(env, dalvik_system_DexPathList$Element, false, "dexFile", "Ldalvik/system/DexFile;");
   java_lang_Thread_daemon = CacheField(env, java_lang_Thread, false, "daemon", "Z");
   java_lang_Thread_group = CacheField(env, java_lang_Thread, false, "group", "Ljava/lang/ThreadGroup;");
   java_lang_Thread_lock = CacheField(env, java_lang_Thread, false, "lock", "Ljava/lang/Object;");
diff --git a/runtime/well_known_classes.h b/runtime/well_known_classes.h
index 7639f50..b10106c 100644
--- a/runtime/well_known_classes.h
+++ b/runtime/well_known_classes.h
@@ -40,7 +40,11 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   static jclass com_android_dex_Dex;
+  static jclass dalvik_system_DexFile;
+  static jclass dalvik_system_DexPathList;
+  static jclass dalvik_system_DexPathList$Element;
   static jclass dalvik_system_PathClassLoader;
+  static jclass java_lang_BootClassLoader;
   static jclass java_lang_ClassLoader;
   static jclass java_lang_ClassNotFoundException;
   static jclass java_lang_Daemons;
@@ -93,6 +97,10 @@
   static jmethodID org_apache_harmony_dalvik_ddmc_DdmServer_broadcast;
   static jmethodID org_apache_harmony_dalvik_ddmc_DdmServer_dispatch;
 
+  static jfieldID dalvik_system_DexFile_cookie;
+  static jfieldID dalvik_system_DexPathList_dexElements;
+  static jfieldID dalvik_system_DexPathList$Element_dexFile;
+  static jfieldID dalvik_system_PathClassLoader_pathList;
   static jfieldID java_lang_reflect_AbstractMethod_artMethod;
   static jfieldID java_lang_reflect_Field_artField;
   static jfieldID java_lang_reflect_Proxy_h;
diff --git a/test/004-JniTest/expected.txt b/test/004-JniTest/expected.txt
index e69de29..49d9cc0 100644
--- a/test/004-JniTest/expected.txt
+++ b/test/004-JniTest/expected.txt
@@ -0,0 +1,29 @@
+Super.<init>
+Super.<init>
+Subclass.<init>
+Super.<init>
+Super.<init>
+Subclass.<init>
+Super.<init>
+RUNNING super object, super class, super nonstatic
+Super.nonstaticMethod
+PASSED super object, super class, super nonstatic
+Super.<init>
+RUNNING super object, sub class, super nonstatic
+Super.nonstaticMethod
+PASSED super object, sub class, super nonstatic
+Super.<init>
+Subclass.<init>
+RUNNING sub object, super class, super nonstatic
+Super.nonstaticMethod
+PASSED sub object, super class, super nonstatic
+Super.<init>
+Subclass.<init>
+RUNNING sub object, sub class, super nonstatic
+Super.nonstaticMethod
+PASSED sub object, sub class, super nonstatic
+Super.<init>
+Subclass.<init>
+RUNNING sub object, sub class, sub nonstatic
+Subclass.nonstaticMethod
+PASSED sub object, sub class, sub nonstatic
diff --git a/test/004-JniTest/jni_test.cc b/test/004-JniTest/jni_test.cc
index f5a1d65..6fc4484 100644
--- a/test/004-JniTest/jni_test.cc
+++ b/test/004-JniTest/jni_test.cc
@@ -353,3 +353,198 @@
 extern "C" JNIEXPORT void JNICALL Java_Main_nativeTestShallowGetStackClass2(JNIEnv* env, jclass) {
   PthreadHelper(&testShallowGetStackClass2);
 }
+
+class JniCallNonvirtualVoidMethodTest {
+ public:
+  explicit JniCallNonvirtualVoidMethodTest(JNIEnv* env)
+      : env_(env),
+        check_jni_ri_(true),
+        check_jni_android_(true),
+        super_(GetClass("JniCallNonvirtualTest")),
+        sub_(GetClass("JniCallNonvirtualTestSubclass")),
+        super_constructor_(GetMethodID(super_, true, "<init>")),
+        super_static_(GetMethodID(super_, false, "staticMethod")),
+        super_nonstatic_(GetMethodID(super_, true, "nonstaticMethod")),
+        sub_constructor_(GetMethodID(sub_, true, "<init>")),
+        sub_static_(GetMethodID(sub_, false, "staticMethod")),
+        sub_nonstatic_(GetMethodID(sub_, true, "nonstaticMethod")),
+        super_field_(GetFieldID(super_, "nonstaticMethodSuperCalled")),
+        sub_field_(GetFieldID(super_, "nonstaticMethodSubCalled")) {}
+
+  void Test() {
+    TestStaticCallNonvirtualMethod();
+    TestNewObject();
+    TestnonstaticCallNonvirtualMethod();
+  }
+
+  JNIEnv* const env_;
+
+  bool const check_jni_ri_;
+  bool const check_jni_android_;
+
+  jclass const super_;
+  jclass const sub_;
+
+  jmethodID const super_constructor_;
+  jmethodID const super_static_;
+  jmethodID const super_nonstatic_;
+  jmethodID const sub_constructor_;
+  jmethodID const sub_static_;
+  jmethodID const sub_nonstatic_;
+
+  jfieldID const super_field_;
+  jfieldID const sub_field_;
+
+ private:
+  jclass GetClass(const char* class_name) {
+    jclass c = env_->FindClass(class_name);
+    if (env_->ExceptionCheck()) {
+      env_->ExceptionDescribe();
+      env_->FatalError(__FUNCTION__);
+    }
+    assert(!env_->ExceptionCheck());
+    assert(c != nullptr);
+    return c;
+  }
+
+  jmethodID GetMethodID(jclass c, bool nonstatic, const char* method_name) {
+    jmethodID m = ((nonstatic) ?
+                   env_->GetMethodID(c, method_name, "()V") :
+                   env_->GetStaticMethodID(c, method_name, "()V"));
+    if (env_->ExceptionCheck()) {
+      env_->ExceptionDescribe();
+      env_->FatalError(__FUNCTION__);
+    }
+    assert(m != nullptr);
+    return m;
+  }
+
+  jobject CallConstructor(jclass c, jmethodID m) {
+    jobject o = env_->NewObject(c, m);
+    if (env_->ExceptionCheck()) {
+      env_->ExceptionDescribe();
+      env_->FatalError(__FUNCTION__);
+    }
+    assert(o != nullptr);
+    return o;
+  }
+
+  void CallMethod(jobject o, jclass c, jmethodID m, bool nonstatic, const char* test_case) {
+    printf("RUNNING %s\n", test_case);
+    env_->CallNonvirtualVoidMethod(o, c, m);
+    bool exception_check = env_->ExceptionCheck();
+    if (c == nullptr || !nonstatic) {
+      if (!exception_check) {
+        printf("FAILED %s due to missing exception\n", test_case);
+        env_->FatalError("Expected NullPointerException with null jclass");
+      }
+      env_->ExceptionClear();
+    } else if (exception_check) {
+      printf("FAILED %s due to pending exception\n", test_case);
+      env_->ExceptionDescribe();
+      env_->FatalError(test_case);
+    }
+    printf("PASSED %s\n", test_case);
+  }
+
+  jfieldID GetFieldID(jclass c, const char* field_name) {
+    jfieldID m = env_->GetFieldID(c, field_name, "Z");
+    if (env_->ExceptionCheck()) {
+      env_->ExceptionDescribe();
+      env_->FatalError(__FUNCTION__);
+    }
+    assert(m != nullptr);
+    return m;
+  }
+
+  jboolean GetBooleanField(jobject o, jfieldID f) {
+    jboolean b = env_->GetBooleanField(o, f);
+    if (env_->ExceptionCheck()) {
+      env_->ExceptionDescribe();
+      env_->FatalError(__FUNCTION__);
+    }
+    return b;
+  }
+
+  void TestStaticCallNonvirtualMethod() {
+    if (!check_jni_ri_&& !check_jni_android_) {
+      CallMethod(nullptr, nullptr, super_static_, false, "null object, null class, super static");
+    }
+    if (!check_jni_android_) {
+      CallMethod(nullptr, super_, super_static_, false, "null object, super class, super static");
+    }
+    if (!check_jni_android_) {
+      CallMethod(nullptr, sub_, super_static_, false, "null object, sub class, super static");
+    }
+
+    if (!check_jni_ri_ && !check_jni_android_) {
+      CallMethod(nullptr, nullptr, sub_static_, false, "null object, null class, sub static");
+    }
+    if (!check_jni_android_) {
+      CallMethod(nullptr, sub_, sub_static_, false, "null object, super class, sub static");
+    }
+    if (!check_jni_android_) {
+      CallMethod(nullptr, super_, sub_static_, false, "null object, super class, sub static");
+    }
+  }
+
+  void TestNewObject() {
+    jobject super_super = CallConstructor(super_, super_constructor_);
+    jobject super_sub = CallConstructor(super_, sub_constructor_);
+    jobject sub_super = CallConstructor(sub_, super_constructor_);
+    jobject sub_sub = CallConstructor(sub_, sub_constructor_);
+
+    assert(env_->IsInstanceOf(super_super, super_));
+    assert(!env_->IsInstanceOf(super_super, sub_));
+
+    // Note that even though we called (and ran) the subclass
+    // constructor, we are not the subclass.
+    assert(env_->IsInstanceOf(super_sub, super_));
+    assert(!env_->IsInstanceOf(super_sub, sub_));
+
+    // Note that even though we called the superclass constructor, we
+    // are still the subclass.
+    assert(env_->IsInstanceOf(sub_super, super_));
+    assert(env_->IsInstanceOf(sub_super, sub_));
+
+    assert(env_->IsInstanceOf(sub_sub, super_));
+    assert(env_->IsInstanceOf(sub_sub, sub_));
+  }
+
+  void TestnonstaticCallNonvirtualMethod(bool super_object, bool super_class, bool super_method, const char* test_case) {
+    if (check_jni_android_) {
+      if (super_object && !super_method) {
+        return;  // We don't allow a call with sub class method on the super class instance.
+      }
+      if (super_class && !super_method) {
+        return;  // We don't allow a call with the sub class method with the super class argument.
+      }
+    }
+    jobject o = ((super_object) ?
+                 CallConstructor(super_, super_constructor_) :
+                 CallConstructor(sub_, sub_constructor_));
+    jclass c = (super_class) ? super_ : sub_;
+    jmethodID m = (super_method) ? super_nonstatic_ : sub_nonstatic_;
+    CallMethod(o, c, m, true, test_case);
+    jboolean super_field = GetBooleanField(o, super_field_);
+    jboolean sub_field = GetBooleanField(o, sub_field_);
+    assert(super_field == super_method);
+    assert(sub_field != super_method);
+  }
+
+  void TestnonstaticCallNonvirtualMethod() {
+    TestnonstaticCallNonvirtualMethod(true, true, true, "super object, super class, super nonstatic");
+    TestnonstaticCallNonvirtualMethod(true, false, true, "super object, sub class, super nonstatic");
+    TestnonstaticCallNonvirtualMethod(true, false, false, "super object, sub class, sub nonstatic");
+    TestnonstaticCallNonvirtualMethod(true, true, false, "super object, super class, sub nonstatic");
+
+    TestnonstaticCallNonvirtualMethod(false, true, true, "sub object, super class, super nonstatic");
+    TestnonstaticCallNonvirtualMethod(false, false, true, "sub object, sub class, super nonstatic");
+    TestnonstaticCallNonvirtualMethod(false, false, false, "sub object, sub class, sub nonstatic");
+    TestnonstaticCallNonvirtualMethod(false, true, false, "sub object, super class, sub nonstatic");
+  }
+};
+
+extern "C" void JNICALL Java_Main_testCallNonvirtual(JNIEnv* env, jclass) {
+  JniCallNonvirtualVoidMethodTest(env).Test();
+}
diff --git a/test/004-JniTest/src/Main.java b/test/004-JniTest/src/Main.java
index 5884bc0..8e92010 100644
--- a/test/004-JniTest/src/Main.java
+++ b/test/004-JniTest/src/Main.java
@@ -32,6 +32,7 @@
         testIsAssignableFromOnPrimitiveTypes();
         testShallowGetCallingClassLoader();
         testShallowGetStackClass2();
+        testCallNonvirtual();
     }
 
     private static native void testFindClassOnAttachedNativeThread();
@@ -94,7 +95,7 @@
 
     // Test sign-extension for values < 32b
 
-    native static byte byteMethod(byte b1, byte b2, byte b3, byte b4, byte b5, byte b6, byte b7,
+    static native byte byteMethod(byte b1, byte b2, byte b3, byte b4, byte b5, byte b6, byte b7,
         byte b8, byte b9, byte b10);
 
     private static void testByteMethod() {
@@ -109,7 +110,7 @@
       }
     }
 
-    native static short shortMethod(short s1, short s2, short s3, short s4, short s5, short s6, short s7,
+    private static native short shortMethod(short s1, short s2, short s3, short s4, short s5, short s6, short s7,
         short s8, short s9, short s10);
 
     private static void testShortMethod() {
@@ -126,7 +127,7 @@
 
     // Test zero-extension for values < 32b
 
-    native static boolean booleanMethod(boolean b1, boolean b2, boolean b3, boolean b4, boolean b5, boolean b6, boolean b7,
+    private static native boolean booleanMethod(boolean b1, boolean b2, boolean b3, boolean b4, boolean b5, boolean b6, boolean b7,
         boolean b8, boolean b9, boolean b10);
 
     private static void testBooleanMethod() {
@@ -139,7 +140,7 @@
       }
     }
 
-    native static char charMethod(char c1, char c2, char c3, char c4, char c5, char c6, char c7,
+    private static native char charMethod(char c1, char c2, char c3, char c4, char c5, char c6, char c7,
         char c8, char c9, char c10);
 
     private static void testCharMethod() {
@@ -168,17 +169,55 @@
       }
     }
 
-    native static boolean nativeIsAssignableFrom(Class<?> from, Class<?> to);
+    private static native boolean nativeIsAssignableFrom(Class<?> from, Class<?> to);
 
-    static void testShallowGetCallingClassLoader() {
+    private static void testShallowGetCallingClassLoader() {
         nativeTestShallowGetCallingClassLoader();
     }
 
-    native static void nativeTestShallowGetCallingClassLoader();
+    private native static void nativeTestShallowGetCallingClassLoader();
 
-    static void testShallowGetStackClass2() {
+    private static void testShallowGetStackClass2() {
         nativeTestShallowGetStackClass2();
     }
 
-    native static void nativeTestShallowGetStackClass2();
+    private static native void nativeTestShallowGetStackClass2();
+
+    private static native void testCallNonvirtual();
+}
+
+class JniCallNonvirtualTest {
+    public boolean nonstaticMethodSuperCalled = false;
+    public boolean nonstaticMethodSubCalled = false;
+
+    private static native void testCallNonvirtual();
+
+    public JniCallNonvirtualTest() {
+        System.out.println("Super.<init>");
+    }
+
+    public static void staticMethod() {
+        System.out.println("Super.staticMethod");
+    }
+
+    public void nonstaticMethod() {
+        System.out.println("Super.nonstaticMethod");
+        nonstaticMethodSuperCalled = true;
+    }
+}
+
+class JniCallNonvirtualTestSubclass extends JniCallNonvirtualTest {
+
+    public JniCallNonvirtualTestSubclass() {
+        System.out.println("Subclass.<init>");
+    }
+
+    public static void staticMethod() {
+        System.out.println("Subclass.staticMethod");
+    }
+
+    public void nonstaticMethod() {
+        System.out.println("Subclass.nonstaticMethod");
+        nonstaticMethodSubCalled = true;
+    }
 }
diff --git a/test/120-hashcode/expected.txt b/test/120-hashcode/expected.txt
new file mode 100644
index 0000000..619c561
--- /dev/null
+++ b/test/120-hashcode/expected.txt
@@ -0,0 +1 @@
+Done.
diff --git a/test/120-hashcode/info.txt b/test/120-hashcode/info.txt
new file mode 100644
index 0000000..80f131d
--- /dev/null
+++ b/test/120-hashcode/info.txt
@@ -0,0 +1 @@
+Check that object hashCode and System.identityHashCode never cause the hash to change.
\ No newline at end of file
diff --git a/test/120-hashcode/src/Main.java b/test/120-hashcode/src/Main.java
new file mode 100644
index 0000000..d2435ce
--- /dev/null
+++ b/test/120-hashcode/src/Main.java
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+public class Main {
+    public static void main(String[] args) {
+        Object o = new Object();
+        // Generate a hashcode and put it in the lock word.
+        int hashOrig = o.hashCode();
+        int hashInflated = 0;
+        int hashSystemOrig = System.identityHashCode(o);
+        int hashSystemInflated = 0;
+        // Inflate the monitor to move the hash from the lock word to the Monitor.
+        synchronized (o) {
+            hashInflated = o.hashCode();
+            hashSystemInflated = System.identityHashCode(o);
+        }
+        // Make sure that all the hashes agree.
+        if (hashOrig != hashInflated || hashOrig != hashSystemOrig ||
+            hashSystemOrig != hashSystemInflated) {
+            System.err.println("hash codes dont match: " + hashOrig + " " + hashInflated + " " +
+            hashSystemOrig + " " + hashSystemInflated);
+        }
+        System.out.println("Done.");
+    }
+}
+
+