blob: cb47082cbf86756a35956fae27f07191a4095e53 [file] [log] [blame]
/*
* Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package vm.runtime.defmeth;
import nsk.share.TestFailure;
import nsk.share.test.TestBase;
import vm.runtime.defmeth.shared.MemoryClassLoader;
import vm.runtime.defmeth.shared.annotation.KnownFailure;
import vm.runtime.defmeth.shared.annotation.NotApplicableFor;
import vm.runtime.defmeth.shared.builder.TestBuilder;
import vm.runtime.defmeth.shared.data.*;
import static jdk.internal.org.objectweb.asm.Opcodes.*;
import vm.runtime.defmeth.shared.DefMethTest;
import java.util.Map;
import static vm.runtime.defmeth.shared.ExecutionMode.*;
/**
* Basic tests on some of the assertions from JVMS.
*/
public class BasicTest extends DefMethTest {
public static void main(String[] args) {
TestBase.runTest(new BasicTest(), args);
}
/*
* JVMS 6.5 invokevirtual
*
* ...
*
* Runtime Exceptions
*
* Otherwise, if the resolved method is not signature polymorphic:
*
*/
/*
* ...
*
* If the resolved method is declared in an interface and the class of
* objectref does not implement the resolved interface, invokevirtual throws
* an IncompatibleClassChangeError.
*/
@KnownFailure(modes = {
REFLECTION, // throws IAE
INVOKE_GENERIC, INVOKE_WITH_ARGS}) // throws ClassCastException
public void testInterfaceNotImplemented() {
TestBuilder b = factory.getBuilder();
Interface I = b.intf("I")
.defaultMethod("m", "()V").emptyBody().build()
.build();
ConcreteClass C = b.clazz("C").build();
Class expectedClass;
if (factory.getExecutionMode().equals("REFLECTION")) {
expectedClass = IllegalArgumentException.class;
} else if (factory.getExecutionMode().equals("INVOKE_WITH_ARGS")) {
// Notes from JDK-8029926 which details reasons behind CCE.
// The code below demonstrates the use of a MethodHandle
// of kind REF_invokeInterface pointing to method I.m.
// Because 'invoke' is called, this MethodHandle is effectively
// wrapped in the type adaptations necessary to accept a C
// as the first argument. ***Before we even get to the point
// of the invokeinterface call to I.m***, the adaptation
// code must run, and that is where the ClassCastException occurs.
// This exception can be thrown from code that is cleanly
// compiled and does no bytecode generation, so an ICCE would
// be inappropriate since no classes are changed.
expectedClass = ClassCastException.class;
} else {
expectedClass = IncompatibleClassChangeError.class;
}
b.test().callSite(I, C, "m", "()V").throws_(expectedClass).done()
.run();
}
/*
* ...
*
* Otherwise, if no method matching the resolved name and descriptor is
* selected, invokevirtual throws an NoSuchMethodError.
*
* ...
*/
@KnownFailure(modes = {
DIRECT, REFLECTION, INVOKE_WITH_ARGS, // NSME, instead of AME
INVOKE_EXACT, INVOKE_GENERIC, INDY}) // IncompatibleClassChangeError, instead of AME
public void testNoMatch() {
TestBuilder b = factory.getBuilder();
Interface I = b.intf("I")
.defaultMethod("m", "(Ljava/lang/Object;)V").emptyBody().build()
.build();
ConcreteClass C = b.clazz("C").implement(I).build();
b.test().callSite(C, C, "m", "()I").throws_(NoSuchMethodError.class).done()
.test().callSite(C, C, "m1", "()V").throws_(NoSuchMethodError.class).done()
.test().callSite(C, C, "m", "(I)V").throws_(NoSuchMethodError.class).done()
.run();
}
/*
* ...
*
* 8025604: Updated specification text for both 5.4.3.3 and 5.4.4.4
* "Otherwise, if any superinterface of C declares a method with the name and
* descriptor specified by the method reference that has set neither
* its ACC_PRIVATE flag nor its ACC_STATIC flag, one of these is arbitrarily
* chosen and method lookup succeeds."
* If method lookup fails, method resolution throws a NoSuchMethodError
*
* ...
*/
public void testNonPublic() {
TestBuilder b = factory.getBuilder();
Interface I = b.intf("I")
.defaultMethod("m1", "()V").private_().emptyBody().build()
.defaultMethod("m2", "()I").private_().returns(1).build()
.build();
ConcreteClass C = b.clazz("C").implement(I).build();
b.test().callSite(C, C, "m1", "()V").throws_(NoSuchMethodError.class).done()
.test().callSite(C, C, "m2", "()I").throws_(NoSuchMethodError.class).done()
.run();
}
/*
* Default method override attempt w/ non-public concrete method.
* Private methods never override any other method.
*
* interface I { int m() default { returns 1; } }
* class C/D/E implements I {
* [private/protected/package-private]
* int m() { returns 2;}
* }
*
*/
public void testNonPublicOverride() {
TestBuilder b = factory.getBuilder();
Interface I = b.intf("I")
.defaultMethod("m", "()I").returns(1).build()
.build();
ConcreteClass C = b.clazz("C").implement(I)
.concreteMethod("m", "()I").private_().returns(2).build()
.build();
ConcreteClass D = b.clazz("D").implement(I)
.concreteMethod("m", "()I").protected_().returns(2).build()
.build();
ConcreteClass E = b.clazz("E").implement(I)
.concreteMethod("m", "()I").package_private().returns(2).build()
.build();
b.test().callSite(I, C, "m", "()I").returns(1).done()
.test().callSite(I, D, "m", "()I").throws_(IllegalAccessError.class).done()
.test().callSite(I, E, "m", "()I").throws_(IllegalAccessError.class).done()
.run();
}
/**
* interface I {
* static { throw new RE()}
* public default void m() {}
* }
*
* class C implements I {}
*
* TEST: C c = new C(); ==> LinkageError
* Static initialization of class C will trigger
* I's static initialization due to I's default method.
*/
public void testStaticInit() throws ClassNotFoundException {
TestBuilder b = factory.getBuilder();
Interface I = b.intf("I")
.defaultMethod("<clinit>", "()V")
.flags(ACC_STATIC)
.throw_(RuntimeException.class)
.build()
.defaultMethod("m", "()V")
.emptyBody().build()
.build();
ConcreteClass C = b.clazz("C").implement(I).build();
b.test().callSite(I, C, "m", "()V").throws_(LinkageError.class).done()
.run();
}
/**
* interface I {
* static { throw new RE()}
* private default void m() {}
* }
*
* class C implements I {}
*
* TEST: C c = new C(); ==> LinkageError
* Static initialization of class C will trigger
* I's static initialization due to I's private concrete method.
*/
public void testStaticInitPrivate() throws ClassNotFoundException {
TestBuilder b = factory.getBuilder();
Interface I = b.intf("I")
.defaultMethod("<clinit>", "()V")
.flags(ACC_STATIC)
.throw_(RuntimeException.class)
.build()
.defaultMethod("m", "()V")
.flags(ACC_PRIVATE)
.emptyBody().build()
.build();
ConcreteClass C = b.clazz("C").implement(I).build();
Class expectedClass;
if (factory.getExecutionMode().equals("REFLECTION")) {
expectedClass = NoSuchMethodException.class;
} else {
expectedClass = LinkageError.class;
}
b.test().callSite(I, C, "m", "()V").throws_(expectedClass).done()
.run();
}
/**
* interface I {
* static { throw new RE()}
* }
* interface J {
* public default int m() { return 1}
*
* class C implements I,J {}
*
* TEST: C c = new C()
* c.m() returns 1
* Static initialization of class C will not trigger
* I's static initialization since I has no concrete methods.
*/
public void testNotStaticInitNoDefault() throws ClassNotFoundException {
TestBuilder b = factory.getBuilder();
Interface I = b.intf("I")
.defaultMethod("<clinit>", "()V")
.flags(ACC_STATIC)
.throw_(RuntimeException.class)
.build()
.build();
Interface J = b.intf("J")
.defaultMethod("m", "()I")
.returns(1).build()
.build();
ConcreteClass C = b.clazz("C").implement(I,J).build();
b.test().callSite(C, C, "m", "()I").returns(1).done()
.run();
}
/*
* Example A.10
*
* Let L1 and L2 be class loaders with different interpretations of the type "A".
*
* Loaded by L1:
* public interface I { public default A m() { return null; } }
*
* Loaded by L2:
* public class C implements I {}
*
* TEST: I o = new C(); o.m() ==> LinkageError;
* TEST: C o = new C(); o.m() ==> LinkageError;
*/
// disabling this test for REFLECTION and INVOKE for now until
// loader constraint issue associated with those modes has been resolved
@NotApplicableFor(modes = { REFLECTION, INVOKE_WITH_ARGS, INVOKE_EXACT, INVOKE_GENERIC, INDY })
public void testLoaderConstraint() throws Exception{
TestBuilder b = factory.getBuilder();
ConcreteClass A = b.clazz("A").build();
Interface I = b.intf("I")
.defaultMethod("m", "()LA;").returnsNewInstance(A).build()
.build();
ConcreteClass C = b.clazz("C").implement(I).build();
b.test().callSite(I, C, "m", "()LA;").throws_(LinkageError.class).done()
.test().callSite(C, C, "m", "()LA;").throws_(LinkageError.class).done()
.prepare(new TestBuilder.LoaderConstructor() {
@Override
public MemoryClassLoader construct(Map<String, byte[]> classFiles) {
final byte[] cfI = classFiles.get("I");
final byte[] cfC = classFiles.get("C");
final byte[] cfA = classFiles.get("A");
final byte[] cfT1 = classFiles.get("Test1_I_C_m");
final byte[] cfT2 = classFiles.get("Test2_C_C_m");
final ClassLoader l1 = new ClassLoader() {
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
switch (name) {
case "I":
return defineClass(name, cfI, 0, cfI.length);
case "A":
return defineClass(name, cfA, 0, cfA.length);
default:
throw new ClassNotFoundException(name);
}
}
};
final MemoryClassLoader l2 = new MemoryClassLoader(classFiles) {
@Override
public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
if ("I".equals(name)) {
return l1.loadClass(name);
} else {
return super.loadClass(name, resolve);
}
}
};
try {
// Need to preload classes, otherwise A will be resolved in the same loader
l1.loadClass("A"); l1.loadClass("I");
l2.loadClass("A"); l2.loadClass("C");
} catch (ClassNotFoundException e) {
throw new TestFailure(e);
}
return l2;
}
}).run();
}
}