From: Alex Light Date: Mon, 22 Feb 2016 21:43:29 +0000 (-0800) Subject: Make JNI work correctly with default methods. X-Git-Tag: android-x86-7.1-r1~340^2~4^2^2~47^2 X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=3612149aee482ab7a17da68b0ef5fef3879729a2;p=android-x86%2Fart.git Make JNI work correctly with default methods. Also adds some tests for JNI and DefaultMethods. Bug: 27259142 Bug: 24618811 Change-Id: I31222e3e41059d803be1dbb0f40e1144ac4bf457 --- diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index a51dd3209..9ed5ec80b 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -1077,10 +1077,8 @@ static void MaybeAddToImageClasses(Handle c, image_classes); } for (auto& m : c->GetVirtualMethods(pointer_size)) { - if (m.IsMiranda() || (true)) { - StackHandleScope<1> hs2(self); - MaybeAddToImageClasses(hs2.NewHandle(m.GetDeclaringClass()), image_classes); - } + StackHandleScope<1> hs2(self); + MaybeAddToImageClasses(hs2.NewHandle(m.GetDeclaringClass()), image_classes); } if (klass->IsArrayClass()) { StackHandleScope<1> hs2(self); diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc index d50528ede..3d3130962 100644 --- a/compiler/image_writer.cc +++ b/compiler/image_writer.cc @@ -917,7 +917,7 @@ void ImageWriter::PruneNonImageClasses() { // Copied methods may be held live by a class which was not an image class but have a // declaring class which is an image class. Set it to the resolution method to be safe and // prevent dangling pointers. - if (method->MightBeCopied() || !KeepClass(declaring_class)) { + if (method->IsCopied() || !KeepClass(declaring_class)) { mirror::DexCache::SetElementPtrSize(resolved_methods, i, resolution_method, diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc index d3b404a3b..fead83926 100644 --- a/compiler/oat_test.cc +++ b/compiler/oat_test.cc @@ -416,7 +416,7 @@ TEST_F(OatTest, WriteRead) { // TODO We should also check copied methods in this test. for (auto& m : klass->GetDeclaredVirtualMethods(pointer_size)) { if (!klass->IsInterface()) { - EXPECT_FALSE(m.MightBeCopied()); + EXPECT_FALSE(m.IsCopied()); } CheckMethod(&m, oat_class.GetOatMethod(method_index), dex_file); ++method_index; diff --git a/runtime/art_method.h b/runtime/art_method.h index f3e8d6bd0..ec00a7b90 100644 --- a/runtime/art_method.h +++ b/runtime/art_method.h @@ -132,9 +132,12 @@ class ArtMethod FINAL { return (GetAccessFlags() & kAccFinal) != 0; } - // Returns true if this method might be copied from another class. - bool MightBeCopied() { - return IsMiranda() || IsDefault() || IsDefaultConflicting(); + bool IsCopied() { + const bool copied = (GetAccessFlags() & kAccCopied) != 0; + // (IsMiranda() || IsDefaultConflicting()) implies copied + DCHECK(!(IsMiranda() || IsDefaultConflicting()) || copied) + << "Miranda or default-conflict methods must always be copied."; + return copied; } bool IsMiranda() { diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 936c98875..9ea082769 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -759,7 +759,7 @@ static void SanityCheckArtMethod(ArtMethod* m, SHARED_REQUIRES(Locks::mutator_lock_) { if (m->IsRuntimeMethod()) { CHECK(m->GetDeclaringClass() == nullptr) << PrettyMethod(m); - } else if (m->MightBeCopied()) { + } else if (m->IsCopied()) { CHECK(m->GetDeclaringClass() != nullptr) << PrettyMethod(m); } else if (expected_class != nullptr) { CHECK_EQ(m->GetDeclaringClassUnchecked(), expected_class) << PrettyMethod(m); @@ -1137,18 +1137,18 @@ class FixupArtMethodArrayVisitor : public ArtMethodVisitor { virtual void Visit(ArtMethod* method) SHARED_REQUIRES(Locks::mutator_lock_) { GcRoot* resolved_types = method->GetDexCacheResolvedTypes(sizeof(void*)); - const bool maybe_copied = method->MightBeCopied(); + const bool is_copied = method->IsCopied(); if (resolved_types != nullptr) { bool in_image_space = false; - if (kIsDebugBuild || maybe_copied) { + if (kIsDebugBuild || is_copied) { in_image_space = header_.GetImageSection(ImageHeader::kSectionDexCacheArrays).Contains( reinterpret_cast(resolved_types) - header_.GetImageBegin()); } // Must be in image space for non-miranda method. - DCHECK(maybe_copied || in_image_space) + DCHECK(is_copied || in_image_space) << resolved_types << " is not in image starting at " << reinterpret_cast(header_.GetImageBegin()); - if (!maybe_copied || in_image_space) { + if (!is_copied || in_image_space) { // Go through the array so that we don't need to do a slow map lookup. method->SetDexCacheResolvedTypes(*reinterpret_cast**>(resolved_types), sizeof(void*)); @@ -1157,15 +1157,15 @@ class FixupArtMethodArrayVisitor : public ArtMethodVisitor { ArtMethod** resolved_methods = method->GetDexCacheResolvedMethods(sizeof(void*)); if (resolved_methods != nullptr) { bool in_image_space = false; - if (kIsDebugBuild || maybe_copied) { + if (kIsDebugBuild || is_copied) { in_image_space = header_.GetImageSection(ImageHeader::kSectionDexCacheArrays).Contains( reinterpret_cast(resolved_methods) - header_.GetImageBegin()); } // Must be in image space for non-miranda method. - DCHECK(maybe_copied || in_image_space) + DCHECK(is_copied || in_image_space) << resolved_methods << " is not in image starting at " << reinterpret_cast(header_.GetImageBegin()); - if (!maybe_copied || in_image_space) { + if (!is_copied || in_image_space) { // Go through the array so that we don't need to do a slow map lookup. method->SetDexCacheResolvedMethods(*reinterpret_cast(resolved_methods), sizeof(void*)); @@ -6459,7 +6459,7 @@ bool ClassLinker::LinkInterfaceMethods( for (ArtMethod* mir_method : miranda_methods) { ArtMethod& new_method = *out; new_method.CopyFrom(mir_method, image_pointer_size_); - new_method.SetAccessFlags(new_method.GetAccessFlags() | kAccMiranda); + new_method.SetAccessFlags(new_method.GetAccessFlags() | kAccMiranda | kAccCopied); DCHECK_NE(new_method.GetAccessFlags() & kAccAbstract, 0u) << "Miranda method should be abstract!"; move_table.emplace(mir_method, &new_method); @@ -6478,7 +6478,9 @@ bool ClassLinker::LinkInterfaceMethods( // yet it shouldn't have methods that are skipping access checks. // TODO This is rather arbitrary. We should maybe support classes where only some of its // methods are skip_access_checks. - new_method.SetAccessFlags((new_method.GetAccessFlags() | kAccDefault) & ~kAccSkipAccessChecks); + constexpr uint32_t kSetFlags = kAccDefault | kAccCopied; + constexpr uint32_t kMaskFlags = ~kAccSkipAccessChecks; + new_method.SetAccessFlags((new_method.GetAccessFlags() | kSetFlags) & kMaskFlags); move_table.emplace(def_method, &new_method); ++out; } @@ -6489,7 +6491,7 @@ bool ClassLinker::LinkInterfaceMethods( // this as a default, non-abstract method, since thats what it is. Also clear the // kAccSkipAccessChecks bit since this class hasn't been verified yet it shouldn't have // methods that are skipping access checks. - constexpr uint32_t kSetFlags = kAccDefault | kAccDefaultConflict; + constexpr uint32_t kSetFlags = kAccDefault | kAccDefaultConflict | kAccCopied; constexpr uint32_t kMaskFlags = ~(kAccAbstract | kAccSkipAccessChecks); new_method.SetAccessFlags((new_method.GetAccessFlags() | kSetFlags) & kMaskFlags); DCHECK(new_method.IsDefaultConflicting()); diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc index 5c3029a5f..488826b6c 100644 --- a/runtime/class_linker_test.cc +++ b/runtime/class_linker_test.cc @@ -263,7 +263,7 @@ class ClassLinkerTest : public CommonRuntimeTest { for (ArtMethod& method : klass->GetCopiedMethods(sizeof(void*))) { AssertMethod(&method); EXPECT_FALSE(method.IsDirect()); - EXPECT_TRUE(method.MightBeCopied()); + EXPECT_TRUE(method.IsCopied()); EXPECT_TRUE(method.GetDeclaringClass()->IsInterface()) << "declaring class: " << PrettyClass(method.GetDeclaringClass()); EXPECT_TRUE(method.GetDeclaringClass()->IsAssignableFrom(klass.Get())) diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h index 3f806d3ca..19584edf7 100644 --- a/runtime/mirror/class-inl.h +++ b/runtime/mirror/class-inl.h @@ -502,7 +502,7 @@ inline ArtMethod* Class::FindVirtualMethodForVirtualOrInterface(ArtMethod* metho if (method->IsDirect()) { return method; } - if (method->GetDeclaringClass()->IsInterface() && !method->IsMiranda()) { + if (method->GetDeclaringClass()->IsInterface() && !method->IsCopied()) { return FindVirtualMethodForInterface(method, pointer_size); } return FindVirtualMethodForVirtual(method, pointer_size); diff --git a/runtime/modifiers.h b/runtime/modifiers.h index ed4c5fc76..c31b22ee8 100644 --- a/runtime/modifiers.h +++ b/runtime/modifiers.h @@ -50,6 +50,11 @@ static constexpr uint32_t kAccSkipAccessChecks = 0x00080000; // method (de // Used by a class to denote that the verifier has attempted to check it at least once. static constexpr uint32_t kAccVerificationAttempted = 0x00080000; // class (runtime) static constexpr uint32_t kAccFastNative = 0x00080000; // method (dex only) +// This is set by the class linker during LinkInterfaceMethods. It is used by a method to represent +// that it was copied from its declaring class into another class. All methods marked kAccMiranda +// and kAccDefaultConflict will have this bit set. Any kAccDefault method contained in the methods_ +// array of a concrete class will also have this bit set. +static constexpr uint32_t kAccCopied = 0x00100000; // method (runtime) static constexpr uint32_t kAccMiranda = 0x00200000; // method (dex only) static constexpr uint32_t kAccDefault = 0x00400000; // method (runtime) // This is set by the class linker during LinkInterfaceMethods. Prior to that point we do not know diff --git a/test/004-JniTest/expected.txt b/test/004-JniTest/expected.txt index 86ab37e1e..155c6ae5f 100644 --- a/test/004-JniTest/expected.txt +++ b/test/004-JniTest/expected.txt @@ -28,3 +28,30 @@ Subclass. RUNNING sub object, sub class, sub nonstatic Subclass.nonstaticMethod PASSED sub object, sub class, sub nonstatic +Calling method ConcreteClass->JniCallNonOverridenDefaultMethod on object of type ConcreteClass +DefaultInterface.JniCallNonOverridenDefaultMethod +Calling method ConcreteClass->JniCallOverridenDefaultMethod on object of type ConcreteClass +ConcreteClass.JniCallOverridenDefaultMethod +Calling method ConcreteClass->JniCallOverridenDefaultMethodWithSuper on object of type ConcreteClass +ConcreteClass.JniCallOverridenDefaultMethodWithSuper +DefaultInterface.JniCallOverridenDefaultMethod +Calling method ConcreteClass->JniCallOverridenAbstractMethod on object of type ConcreteClass +ConcreteClass.JniCallOverridenAbstractMethod +Calling method ConcreteClass->JniCallConflictDefaultMethod on object of type ConcreteClass +EXCEPTION OCCURED: java.lang.IncompatibleClassChangeError: Conflicting default method implementations void ConflictInterface.JniCallConflictDefaultMethod() +Calling method ConcreteClass->JniCallSoftConflictMethod on object of type ConcreteClass +DefaultInterface.JniCallSoftConflictMethod +Calling method DefaultInterface->JniCallNonOverridenDefaultMethod on object of type ConcreteClass +DefaultInterface.JniCallNonOverridenDefaultMethod +Calling method DefaultInterface->JniCallOverridenDefaultMethod on object of type ConcreteClass +ConcreteClass.JniCallOverridenDefaultMethod +Calling method DefaultInterface->JniCallOverridenAbstractMethod on object of type ConcreteClass +ConcreteClass.JniCallOverridenAbstractMethod +Calling method DefaultInterface->JniCallConflictDefaultMethod on object of type ConcreteClass +EXCEPTION OCCURED: java.lang.IncompatibleClassChangeError: Conflicting default method implementations void ConflictInterface.JniCallConflictDefaultMethod() +Calling method DefaultInterface->JniCallSoftConflictMethod on object of type ConcreteClass +DefaultInterface.JniCallSoftConflictMethod +Calling method AbstractInterface->JniCallSoftConflictMethod on object of type ConcreteClass +DefaultInterface.JniCallSoftConflictMethod +Calling method ConflictInterface->JniCallConflictDefaultMethod on object of type ConcreteClass +EXCEPTION OCCURED: java.lang.IncompatibleClassChangeError: Conflicting default method implementations void ConflictInterface.JniCallConflictDefaultMethod() diff --git a/test/004-JniTest/jni_test.cc b/test/004-JniTest/jni_test.cc index 70454828f..f632331fe 100644 --- a/test/004-JniTest/jni_test.cc +++ b/test/004-JniTest/jni_test.cc @@ -659,3 +659,65 @@ extern "C" JNIEXPORT void JNICALL Java_Main_enterJniCriticalSection(JNIEnv* env, env->ReleasePrimitiveArrayCritical(array0, data0, 0); } } + +class JniCallDefaultMethodsTest { + public: + explicit JniCallDefaultMethodsTest(JNIEnv* env) + : env_(env), concrete_class_(env_->FindClass("ConcreteClass")) { + assert(!env_->ExceptionCheck()); + assert(concrete_class_ != nullptr); + } + + void Test() { + TestCalls("ConcreteClass", { "JniCallNonOverridenDefaultMethod", + "JniCallOverridenDefaultMethod", + "JniCallOverridenDefaultMethodWithSuper", + "JniCallOverridenAbstractMethod", + "JniCallConflictDefaultMethod", + "JniCallSoftConflictMethod" }); + TestCalls("DefaultInterface", { "JniCallNonOverridenDefaultMethod", + "JniCallOverridenDefaultMethod", + "JniCallOverridenAbstractMethod", + "JniCallConflictDefaultMethod", + "JniCallSoftConflictMethod" }); + TestCalls("AbstractInterface", { "JniCallSoftConflictMethod" }); + TestCalls("ConflictInterface", { "JniCallConflictDefaultMethod" }); + } + + private: + void TestCalls(const char* declaring_class, std::vector methods) { + jmethodID new_method = env_->GetMethodID(concrete_class_, "", "()V"); + jobject obj = env_->NewObject(concrete_class_, new_method); + assert(!env_->ExceptionCheck()); + assert(obj != nullptr); + jclass decl_class = env_->FindClass(declaring_class); + assert(!env_->ExceptionCheck()); + assert(decl_class != nullptr); + for (const char* method : methods) { + jmethodID method_id = env_->GetMethodID(decl_class, method, "()V"); + assert(!env_->ExceptionCheck()); + printf("Calling method %s->%s on object of type ConcreteClass\n", declaring_class, method); + env_->CallVoidMethod(obj, method_id); + if (env_->ExceptionCheck()) { + jthrowable thrown = env_->ExceptionOccurred(); + env_->ExceptionClear(); + jmethodID to_string = env_->GetMethodID( + env_->FindClass("java/lang/Object"), "toString", "()Ljava/lang/String;"); + jstring exception_string = (jstring) env_->CallObjectMethod(thrown, to_string); + assert(!env_->ExceptionCheck()); + const char* exception_string_utf8 = env_->GetStringUTFChars(exception_string, nullptr); + assert(!env_->ExceptionCheck()); + assert(exception_string_utf8 != nullptr); + printf("EXCEPTION OCCURED: %s\n", exception_string_utf8); + env_->ReleaseStringUTFChars(exception_string, exception_string_utf8); + } + } + } + + JNIEnv* env_; + jclass concrete_class_; +}; + +extern "C" JNIEXPORT void JNICALL Java_Main_testCallDefaultMethods(JNIEnv* env) { + JniCallDefaultMethodsTest(env).Test(); +} diff --git a/test/004-JniTest/smali/AbstractInterface.smali b/test/004-JniTest/smali/AbstractInterface.smali new file mode 100644 index 000000000..52b2fc537 --- /dev/null +++ b/test/004-JniTest/smali/AbstractInterface.smali @@ -0,0 +1,26 @@ +# /* +# * Copyright 2016 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. +# */ + +.class public interface LAbstractInterface; +.super Ljava/lang/Object; + +# public interface AbstractInterface { +# public void JniCallSoftConflictMethod(); +# } + +.method public abstract JniCallSoftConflictMethod()V +.end method + diff --git a/test/004-JniTest/smali/ConcreteClass.smali b/test/004-JniTest/smali/ConcreteClass.smali new file mode 100644 index 000000000..a9c072fc2 --- /dev/null +++ b/test/004-JniTest/smali/ConcreteClass.smali @@ -0,0 +1,72 @@ +# /* +# * Copyright 2016 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. +# */ + +.class public LConcreteClass; +.super Ljava/lang/Object; +.implements LDefaultInterface; +.implements LConflictInterface; +.implements LAbstractInterface; + +# public class ConcreteClass implements DefaultInterface, ConflictInterface, AbstractInterface { +# public void JniCallOverridenAbstractMethod() { +# System.out.println("ConcreteClass.JniCallOverridenAbstractMethod"); +# } +# +# public void JniCallOverridenDefaultMethod() { +# System.out.println("ConcreteClass.JniCallOverridenDefaultMethod"); +# } +# +# public void JniCallOverridenDefaultMethodWithSuper() { +# System.out.println("ConcreteClass.JniCallOverridenDefaultMethodWithSuper"); +# DefaultInterface.super.JniCallOverridenDefaultMethod(); +# } +# } + +.method public constructor ()V + .registers 1 + invoke-direct {p0}, Ljava/lang/Object;->()V + return-void +.end method + +.method public JniCallOverridenAbstractMethod()V + .locals 2 + + const-string v0, "ConcreteClass.JniCallOverridenAbstractMethod" + sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream; + invoke-virtual {v1,v0}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V + return-void +.end method + +.method public JniCallOverridenDefaultMethod()V + .locals 2 + + const-string v0, "ConcreteClass.JniCallOverridenDefaultMethod" + sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream; + invoke-virtual {v1,v0}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V + return-void +.end method + +.method public JniCallOverridenDefaultMethodWithSuper()V + .locals 2 + + const-string v0, "ConcreteClass.JniCallOverridenDefaultMethodWithSuper" + sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream; + invoke-virtual {v1,v0}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V + + invoke-super {p0}, LDefaultInterface;->JniCallOverridenDefaultMethod()V + + return-void +.end method diff --git a/test/004-JniTest/smali/ConflictInterface.smali b/test/004-JniTest/smali/ConflictInterface.smali new file mode 100644 index 000000000..fc3d474df --- /dev/null +++ b/test/004-JniTest/smali/ConflictInterface.smali @@ -0,0 +1,35 @@ +# /* +# * Copyright 2016 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. +# */ + +.class public interface LConflictInterface; +.super Ljava/lang/Object; + +# public interface ConflictInterface { +# public default void JniCallConflictDefaultMethod() { +# System.out.println("ConflictInterface.JniCallConflictDefaultMethod"); +# } +# +# } + +.method public JniCallConflictDefaultMethod()V + .locals 2 + + const-string v0, "ConflictInterface.JniCallConflictDefaultMethod" + sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream; + invoke-virtual {v1,v0}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V + return-void +.end method + diff --git a/test/004-JniTest/smali/DefaultInterface.smali b/test/004-JniTest/smali/DefaultInterface.smali new file mode 100644 index 000000000..1ee872154 --- /dev/null +++ b/test/004-JniTest/smali/DefaultInterface.smali @@ -0,0 +1,77 @@ +# /* +# * Copyright 2016 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. +# */ + +.class public interface LDefaultInterface; +.super Ljava/lang/Object; + +# public interface DefaultInterface { +# public default void JniCallNonOverridenDefaultMethod() { +# System.out.println("DefaultInterface.JniCallNonOverridenDefaultMethod"); +# } +# +# public default void JniCallOverridenDefaultMethod() { +# System.out.println("DefaultInterface.JniCallOverridenDefaultMethod"); +# } +# +# public void JniCallOverridenAbstractMethod(); +# +# public default void JniCallConflictDefaultMethod() { +# System.out.println("DefaultInterface.JniCallConflictDefaultMethod"); +# } +# +# public default void JniCallSoftConflictMethod() { +# System.out.println("DefaultInterface.JniCallSoftConflictMethod"); +# } +# } + +.method public JniCallNonOverridenDefaultMethod()V + .locals 2 + + const-string v0, "DefaultInterface.JniCallNonOverridenDefaultMethod" + sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream; + invoke-virtual {v1,v0}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V + return-void +.end method + +.method public JniCallOverridenDefaultMethod()V + .locals 2 + + const-string v0, "DefaultInterface.JniCallOverridenDefaultMethod" + sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream; + invoke-virtual {v1,v0}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V + return-void +.end method + +.method public abstract JniCallOverridenAbstractMethod()V +.end method + +.method public JniCallConflictDefaultMethod()V + .locals 2 + + const-string v0, "DefaultInterface.JniCallConflictDefaultMethod" + sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream; + invoke-virtual {v1,v0}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V + return-void +.end method + +.method public JniCallSoftConflictMethod()V + .locals 2 + + const-string v0, "DefaultInterface.JniCallSoftConflictMethod" + sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream; + invoke-virtual {v1,v0}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V + return-void +.end method diff --git a/test/004-JniTest/src/Main.java b/test/004-JniTest/src/Main.java index 5c39ede68..9f4a8522e 100644 --- a/test/004-JniTest/src/Main.java +++ b/test/004-JniTest/src/Main.java @@ -39,8 +39,11 @@ public class Main { testRemoveLocalObject(); testProxyGetMethodID(); testJniCriticalSectionAndGc(); + testCallDefaultMethods(); } + private static native void testCallDefaultMethods(); + private static native void testFindClassOnAttachedNativeThread(); private static boolean testFindFieldOnAttachedNativeThreadField; @@ -121,7 +124,7 @@ public class Main { private static void testRemoveLocalObject() { removeLocalObject(new Object()); } - + 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);