8016839: JSR292: AME instead of IAE when calling a method
Catch missing-because-illegal case for itable entries and use an exception-throwing method instead of null. Reviewed-by: acorn, jrose, coleenp
This commit is contained in:
parent
3646381ba6
commit
78f1afbf45
hotspot
src/share/vm
test/compiler/jsr292/methodHandleExceptions
@ -165,6 +165,7 @@ class SymbolPropertyTable;
|
||||
\
|
||||
do_klass(StringBuffer_klass, java_lang_StringBuffer, Pre ) \
|
||||
do_klass(StringBuilder_klass, java_lang_StringBuilder, Pre ) \
|
||||
do_klass(misc_Unsafe_klass, sun_misc_Unsafe, Pre ) \
|
||||
\
|
||||
/* It's NULL in non-1.4 JDKs. */ \
|
||||
do_klass(StackTraceElement_klass, java_lang_StackTraceElement, Opt ) \
|
||||
|
@ -331,6 +331,7 @@
|
||||
template(findNative_name, "findNative") \
|
||||
template(deadChild_name, "deadChild") \
|
||||
template(addClass_name, "addClass") \
|
||||
template(throwIllegalAccessError_name, "throwIllegalAccessError") \
|
||||
template(getFromClass_name, "getFromClass") \
|
||||
template(dispatch_name, "dispatch") \
|
||||
template(getSystemClassLoader_name, "getSystemClassLoader") \
|
||||
|
@ -120,6 +120,7 @@ oop Universe::_null_ptr_exception_instance = NULL;
|
||||
oop Universe::_arithmetic_exception_instance = NULL;
|
||||
oop Universe::_virtual_machine_error_instance = NULL;
|
||||
oop Universe::_vm_exception = NULL;
|
||||
Method* Universe::_throw_illegal_access_error = NULL;
|
||||
Array<int>* Universe::_the_empty_int_array = NULL;
|
||||
Array<u2>* Universe::_the_empty_short_array = NULL;
|
||||
Array<Klass*>* Universe::_the_empty_klass_array = NULL;
|
||||
@ -1096,6 +1097,18 @@ bool universe_post_init() {
|
||||
Universe::_finalizer_register_cache->init(
|
||||
SystemDictionary::Finalizer_klass(), m);
|
||||
|
||||
InstanceKlass::cast(SystemDictionary::misc_Unsafe_klass())->link_class(CHECK_false);
|
||||
m = InstanceKlass::cast(SystemDictionary::misc_Unsafe_klass())->find_method(
|
||||
vmSymbols::throwIllegalAccessError_name(),
|
||||
vmSymbols::void_method_signature());
|
||||
if (m != NULL && !m->is_static()) {
|
||||
// Note null is okay; this method is used in itables, and if it is null,
|
||||
// then AbstractMethodError is thrown instead.
|
||||
tty->print_cr("Unable to link/verify Unsafe.throwIllegalAccessError method");
|
||||
return false; // initialization failed (cannot throw exception yet)
|
||||
}
|
||||
Universe::_throw_illegal_access_error = m;
|
||||
|
||||
// Setup method for registering loaded classes in class loader vector
|
||||
InstanceKlass::cast(SystemDictionary::ClassLoader_klass())->link_class(CHECK_false);
|
||||
m = InstanceKlass::cast(SystemDictionary::ClassLoader_klass())->find_method(vmSymbols::addClass_name(), vmSymbols::class_void_signature());
|
||||
|
@ -149,6 +149,8 @@ class Universe: AllStatic {
|
||||
static LatestMethodCache* _loader_addClass_cache; // method for registering loaded classes in class loader vector
|
||||
static LatestMethodCache* _pd_implies_cache; // method for checking protection domain attributes
|
||||
|
||||
static Method* _throw_illegal_access_error;
|
||||
|
||||
// preallocated error objects (no backtrace)
|
||||
static oop _out_of_memory_error_java_heap;
|
||||
static oop _out_of_memory_error_metaspace;
|
||||
@ -305,6 +307,7 @@ class Universe: AllStatic {
|
||||
static oop arithmetic_exception_instance() { return _arithmetic_exception_instance; }
|
||||
static oop virtual_machine_error_instance() { return _virtual_machine_error_instance; }
|
||||
static oop vm_exception() { return _vm_exception; }
|
||||
static Method* throw_illegal_access_error() { return _throw_illegal_access_error; }
|
||||
|
||||
static Array<int>* the_empty_int_array() { return _the_empty_int_array; }
|
||||
static Array<u2>* the_empty_short_array() { return _the_empty_short_array; }
|
||||
|
@ -1076,7 +1076,12 @@ void klassItable::initialize_itable_for_interface(int method_table_offset, Klass
|
||||
LinkResolver::lookup_instance_method_in_klasses(target, _klass, m->name(), m->signature(), CHECK);
|
||||
}
|
||||
if (target == NULL || !target->is_public() || target->is_abstract()) {
|
||||
// Entry do not resolve. Leave it empty
|
||||
// Entry does not resolve. Leave it empty for AbstractMethodError.
|
||||
if (!(target == NULL) && !target->is_public()) {
|
||||
// Stuff an IllegalAccessError throwing method in there instead.
|
||||
itableOffsetEntry::method_entry(_klass(), method_table_offset)[m->itable_index()].
|
||||
initialize(Universe::throw_illegal_access_error());
|
||||
}
|
||||
} else {
|
||||
// Entry did resolve, check loader constraints before initializing
|
||||
// if checkconstraints requested
|
||||
|
@ -1,3 +1,12 @@
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarOutputStream;
|
||||
|
||||
/*
|
||||
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
@ -23,12 +32,63 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* A minimal classloader for loading bytecodes that could not result from
|
||||
* properly compiled Java.
|
||||
* A ByteClassLoader is used to define classes from collections of bytes, as
|
||||
* well as loading classes in the usual way. It includes options to write the
|
||||
* classes to files in a jar, or to read the classes from jars in a later or
|
||||
* debugging run.
|
||||
*
|
||||
* If Boolean property byteclassloader.verbose is true, be chatty about jar
|
||||
* file operations.
|
||||
*
|
||||
* @author dr2chase
|
||||
*/
|
||||
public class ByteClassLoader extends ClassLoader {
|
||||
public class ByteClassLoader extends URLClassLoader {
|
||||
|
||||
final static boolean verbose
|
||||
= Boolean.getBoolean("byteclassloader.verbose");
|
||||
|
||||
final boolean read;
|
||||
final JarOutputStream jos;
|
||||
final String jar_name;
|
||||
|
||||
/**
|
||||
* Make a new ByteClassLoader.
|
||||
*
|
||||
* @param jar_name Basename of jar file to be read/written by this classloader.
|
||||
* @param read If true, read classes from jar file instead of from parameter.
|
||||
* @param write If true, write classes to jar files for offline study/use.
|
||||
*
|
||||
* @throws FileNotFoundException
|
||||
* @throws IOException
|
||||
*/
|
||||
public ByteClassLoader(String jar_name, boolean read, boolean write)
|
||||
throws FileNotFoundException, IOException {
|
||||
super(read
|
||||
? new URL[]{new URL("file:" + jar_name + ".jar")}
|
||||
: new URL[0]);
|
||||
this.read = read;
|
||||
this.jar_name = jar_name;
|
||||
this.jos = write
|
||||
? new JarOutputStream(
|
||||
new BufferedOutputStream(
|
||||
new FileOutputStream(jar_name + ".jar"))) : null;
|
||||
if (read && write) {
|
||||
throw new Error("At most one of read and write may be true.");
|
||||
}
|
||||
}
|
||||
|
||||
private static void writeJarredFile(JarOutputStream jos, String file, String suffix, byte[] bytes) {
|
||||
String fileName = file.replace(".", "/") + "." + suffix;
|
||||
JarEntry ze = new JarEntry(fileName);
|
||||
try {
|
||||
ze.setSize(bytes.length);
|
||||
jos.putNextEntry(ze);
|
||||
jos.write(bytes);
|
||||
jos.closeEntry();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* (pre)load class name using classData for the definition.
|
||||
*
|
||||
@ -36,9 +96,36 @@ public class ByteClassLoader extends ClassLoader {
|
||||
* @param classData
|
||||
* @return
|
||||
*/
|
||||
public Class<?> loadBytes(String name, byte[] classData) {
|
||||
Class<?> clazz = defineClass(name, classData, 0, classData.length);
|
||||
resolveClass(clazz);
|
||||
return clazz;
|
||||
public Class<?> loadBytes(String name, byte[] classData) throws ClassNotFoundException {
|
||||
if (jos != null) {
|
||||
if (verbose) {
|
||||
System.out.println("ByteClassLoader: writing " + name);
|
||||
}
|
||||
writeJarredFile(jos, name, "class", classData);
|
||||
}
|
||||
|
||||
Class<?> clazz = null;
|
||||
if (read) {
|
||||
if (verbose) {
|
||||
System.out.println("ByteClassLoader: reading " + name + " from " + jar_name);
|
||||
}
|
||||
clazz = loadClass(name);
|
||||
} else {
|
||||
clazz = defineClass(name, classData, 0, classData.length);
|
||||
resolveClass(clazz);
|
||||
}
|
||||
return clazz;
|
||||
}
|
||||
|
||||
public void close() {
|
||||
if (jos != null) {
|
||||
try {
|
||||
if (verbose) {
|
||||
System.out.println("ByteClassLoader: closing " + jar_name);
|
||||
}
|
||||
jos.close();
|
||||
} catch (IOException ex) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21,50 +21,127 @@
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import jdk.internal.org.objectweb.asm.ClassWriter;
|
||||
import jdk.internal.org.objectweb.asm.Handle;
|
||||
import jdk.internal.org.objectweb.asm.MethodVisitor;
|
||||
import jdk.internal.org.objectweb.asm.Opcodes;
|
||||
import p.Dok;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8025260
|
||||
* @summary Ensure that AbstractMethodError is thrown, not NullPointerException, through MethodHandles::jump_from_method_handle code path
|
||||
* @test @bug 8025260 8016839
|
||||
* @summary Ensure that AbstractMethodError and IllegalAccessError are thrown appropriately, not NullPointerException
|
||||
*
|
||||
* @compile -XDignore.symbol.file TestAMEnotNPE.java ByteClassLoader.java p/C.java p/Dok.java p/E.java p/F.java p/I.java p/Tdirect.java p/Treflect.java
|
||||
*
|
||||
* @compile -XDignore.symbol.file ByteClassLoader.java I.java C.java TestAMEnotNPE.java
|
||||
* @run main/othervm TestAMEnotNPE
|
||||
* @run main/othervm -Xint TestAMEnotNPE
|
||||
* @run main/othervm -Xcomp TestAMEnotNPE
|
||||
*/
|
||||
|
||||
public class TestAMEnotNPE implements Opcodes {
|
||||
|
||||
static boolean writeJarFiles = false;
|
||||
static boolean readJarFiles = false;
|
||||
|
||||
/**
|
||||
* The bytes for D, a NOT abstract class extending abstract class C
|
||||
* without supplying an implementation for abstract method m.
|
||||
* There is a default method in the interface I, but it should lose to
|
||||
* the abstract class.
|
||||
* Optional command line parameter (any case-insensitive prefix of)
|
||||
* "writejarfiles" or "readjarfiles".
|
||||
*
|
||||
* "Writejarfiles" creates a jar file for each different set of tested classes.
|
||||
* "Readjarfiles" causes the classloader to use the copies of the classes
|
||||
* found in the corresponding jar files.
|
||||
*
|
||||
* Jarfilenames look something like pD_ext_pF (p.D extends p.F)
|
||||
* and qD_m_pp_imp_pI (q.D with package-private m implements p.I)
|
||||
*
|
||||
*/
|
||||
public static void main(String args[]) throws Throwable {
|
||||
ArrayList<Throwable> lt = new ArrayList<Throwable>();
|
||||
|
||||
class D extends C {
|
||||
D() { super(); }
|
||||
// does not define m
|
||||
}
|
||||
if (args.length > 0) {
|
||||
String a0 = args[0].toLowerCase();
|
||||
if (a0.length() > 0) {
|
||||
writeJarFiles = ("writejarfiles").startsWith(a0);
|
||||
readJarFiles = ("readjarfiles").startsWith(a0);
|
||||
}
|
||||
if (!(writeJarFiles || readJarFiles)) {
|
||||
throw new Error("Command line parameter (if any) should be prefix of writeJarFiles or readJarFiles");
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
System.out.println("TRYING p.D.m PRIVATE interface-invoked as p.I.m, p.D extends p.F, p.F.m FINAL");
|
||||
tryAndCheckThrown(lt, bytesForDprivateSubWhat("p/F"),
|
||||
"p.D extends p.F (p.F implements p.I, FINAL public m), private m",
|
||||
IllegalAccessError.class, "pD_ext_pF");
|
||||
// We'll take either a VerifyError (pre 2013-11-30)
|
||||
// or an IllegalAccessError (post 2013-11-22)
|
||||
} catch (VerifyError ve) {
|
||||
System.out.println("Saw expected VerifyError " + ve);
|
||||
}
|
||||
System.out.println();
|
||||
|
||||
System.out.println("TRYING p.D.m PRIVATE interface-invoked as p.I.m, p.D extends p.E");
|
||||
tryAndCheckThrown(lt, bytesForDprivateSubWhat("p/E"),
|
||||
"p.D extends p.E (p.E implements p.I, public m), private m",
|
||||
IllegalAccessError.class, "pD_ext_pE");
|
||||
|
||||
System.out.println("TRYING p.D.m ABSTRACT interface-invoked as p.I.m");
|
||||
tryAndCheckThrown(lt, bytesForD(),
|
||||
"D extends abstract C, no m",
|
||||
AbstractMethodError.class, "pD_ext_pC");
|
||||
|
||||
System.out.println("TRYING q.D.m PACKAGE interface-invoked as p.I.m");
|
||||
tryAndCheckThrown(lt, "q.D", bytesForDsomeAccess("q/D", 0),
|
||||
"q.D implements p.I, protected m", IllegalAccessError.class,
|
||||
"qD_m_pp_imp_pI");
|
||||
|
||||
// Note jar file name is used in the plural-arg case.
|
||||
System.out.println("TRYING p.D.m PRIVATE interface-invoked as p.I.m");
|
||||
tryAndCheckThrown(lt, bytesForDsomeAccess("p/D", ACC_PRIVATE),
|
||||
"p.D implements p.I, private m",
|
||||
IllegalAccessError.class, "pD_m_pri_imp_pI");
|
||||
|
||||
// Plural-arg test.
|
||||
System.out.println("TRYING p.D.m PRIVATE MANY ARG interface-invoked as p.I.m");
|
||||
tryAndCheckThrownMany(lt, bytesForDsomeAccess("p/D", ACC_PRIVATE),
|
||||
"p.D implements p.I, private m", IllegalAccessError.class);
|
||||
|
||||
if (lt.size() > 0) {
|
||||
System.out.flush();
|
||||
Thread.sleep(250); // This de-interleaves output and error in Netbeans, sigh.
|
||||
for (Throwable th : lt)
|
||||
System.err.println(th);
|
||||
throw new Error("Test failed, there were " + lt.size() + " failures listed above");
|
||||
} else {
|
||||
System.out.println("ALL PASS, HOORAY!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The bytes for D, a NOT abstract class extending abstract class C without
|
||||
* supplying an implementation for abstract method m. There is a default
|
||||
* method in the interface I, but it should lose to the abstract class.
|
||||
*
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public static byte[] bytesForD() throws Exception {
|
||||
|
||||
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES|ClassWriter.COMPUTE_MAXS);
|
||||
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES
|
||||
| ClassWriter.COMPUTE_MAXS);
|
||||
MethodVisitor mv;
|
||||
|
||||
cw.visit(V1_8, ACC_PUBLIC + ACC_SUPER, "D", null, "C", null);
|
||||
cw.visit(V1_8, ACC_PUBLIC + ACC_SUPER, "p/D", null, "p/C", null);
|
||||
|
||||
{
|
||||
mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
|
||||
mv.visitCode();
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitMethodInsn(INVOKESPECIAL, "C", "<init>", "()V");
|
||||
mv.visitMethodInsn(INVOKESPECIAL, "p/C", "<init>", "()V");
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(0, 0);
|
||||
mv.visitEnd();
|
||||
@ -74,70 +151,346 @@ public class TestAMEnotNPE implements Opcodes {
|
||||
return cw.toByteArray();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The bytecodes for an invokeExact of a particular methodHandle, I.m, invoked on a D
|
||||
|
||||
class T {
|
||||
T() { super(); } // boring constructor
|
||||
int test() {
|
||||
MethodHandle mh = `I.m():int`;
|
||||
D d = new D();
|
||||
return mh.invokeExact(d); // Should explode here, AbstractMethodError
|
||||
}
|
||||
}
|
||||
|
||||
* The bytes for D, implements I, does not extend C, declares m()I with
|
||||
* access method_acc.
|
||||
*
|
||||
* @param d_name Name of class defined
|
||||
* @param method_acc Accessibility of that class's method m.
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public static byte[] bytesForT() throws Exception {
|
||||
public static byte[] bytesForDsomeAccess(String d_name, int method_acc) throws Exception {
|
||||
return bytesForSomeDsubSomethingSomeAccess(d_name, "java/lang/Object", method_acc);
|
||||
}
|
||||
|
||||
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES|ClassWriter.COMPUTE_MAXS);
|
||||
/**
|
||||
* The bytes for D implements I, extends some class, declares m()I as
|
||||
* private.
|
||||
*
|
||||
* Invokeinterface of I.m applied to this D should throw IllegalAccessError
|
||||
*
|
||||
* @param sub_what The name of the class that D will extend.
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public static byte[] bytesForDprivateSubWhat(String sub_what) throws Exception {
|
||||
return bytesForSomeDsubSomethingSomeAccess("p/D", sub_what, ACC_PRIVATE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bytes for a class with name d_name (presumably "D" in some
|
||||
* package), extending some class with name sub_what, implementing p.I,
|
||||
* and defining two methods m() and m(11args) with access method_acc.
|
||||
*
|
||||
* @param d_name Name of class that is defined
|
||||
* @param sub_what Name of class that it extends
|
||||
* @param method_acc Accessibility of method(s) m in defined class.
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public static byte[] bytesForSomeDsubSomethingSomeAccess
|
||||
(String d_name, String sub_what, int method_acc)
|
||||
throws Exception {
|
||||
|
||||
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES
|
||||
| ClassWriter.COMPUTE_MAXS);
|
||||
MethodVisitor mv;
|
||||
String[] interfaces = {"p/I"};
|
||||
|
||||
cw.visit(V1_8, ACC_PUBLIC + ACC_SUPER, "T", null, "java/lang/Object", null);
|
||||
cw.visit(V1_8, ACC_PUBLIC + ACC_SUPER, d_name, null, sub_what, interfaces);
|
||||
{
|
||||
mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
|
||||
mv.visitCode();
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
|
||||
mv.visitMethodInsn(INVOKESPECIAL, sub_what, "<init>", "()V");
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(0,0);
|
||||
mv.visitMaxs(0, 0);
|
||||
mv.visitEnd();
|
||||
}
|
||||
// int m() {return 3;}
|
||||
{
|
||||
mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "test", "()I", null, null);
|
||||
mv = cw.visitMethod(method_acc, "m", "()I", null, null);
|
||||
mv.visitCode();
|
||||
mv.visitLdcInsn(new Handle(Opcodes.H_INVOKEINTERFACE, "I", "m", "()I"));
|
||||
mv.visitTypeInsn(NEW, "D");
|
||||
mv.visitInsn(DUP);
|
||||
mv.visitMethodInsn(INVOKESPECIAL, "D", "<init>", "()V");
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", "invokeExact", "(LI;)I");
|
||||
mv.visitLdcInsn(new Integer(3));
|
||||
mv.visitInsn(IRETURN);
|
||||
mv.visitMaxs(0,0);
|
||||
mv.visitMaxs(0, 0);
|
||||
mv.visitEnd();
|
||||
}
|
||||
// int m(11args) {return 3;}
|
||||
{
|
||||
mv = cw.visitMethod(method_acc, "m", "(BCSIJ"
|
||||
+ "Ljava/lang/Object;"
|
||||
+ "Ljava/lang/Object;"
|
||||
+ "Ljava/lang/Object;"
|
||||
+ "Ljava/lang/Object;"
|
||||
+ "Ljava/lang/Object;"
|
||||
+ "Ljava/lang/Object;"
|
||||
+ ")I", null, null);
|
||||
mv.visitCode();
|
||||
mv.visitLdcInsn(new Integer(3));
|
||||
mv.visitInsn(IRETURN);
|
||||
mv.visitMaxs(0, 0);
|
||||
mv.visitEnd();
|
||||
}
|
||||
cw.visitEnd();
|
||||
return cw.toByteArray();
|
||||
}
|
||||
|
||||
public static void main(String args[] ) throws Throwable {
|
||||
ByteClassLoader bcl = new ByteClassLoader();
|
||||
Class<?> d = bcl.loadBytes("D", bytesForD());
|
||||
Class<?> t = bcl.loadBytes("T", bytesForT());
|
||||
/**
|
||||
* The bytecodes for a class p/T defining a methods test() and test(11args)
|
||||
* that contain an invokeExact of a particular methodHandle, I.m.
|
||||
*
|
||||
* Test will be passed values that may imperfectly implement I,
|
||||
* and thus may in turn throw exceptions.
|
||||
*
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public static byte[] bytesForT() throws Exception {
|
||||
|
||||
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES
|
||||
| ClassWriter.COMPUTE_MAXS);
|
||||
MethodVisitor mv;
|
||||
|
||||
cw.visit(V1_8, ACC_PUBLIC + ACC_SUPER, "p/T", null, "java/lang/Object", null);
|
||||
{
|
||||
mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
|
||||
mv.visitCode();
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(0, 0);
|
||||
mv.visitEnd();
|
||||
}
|
||||
// static int test(I)
|
||||
{
|
||||
mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "test", "(Lp/I;)I", null, null);
|
||||
mv.visitCode();
|
||||
mv.visitLdcInsn(new Handle(Opcodes.H_INVOKEINTERFACE, "p/I", "m", "()I"));
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle",
|
||||
"invokeExact", "(Lp/I;)I");
|
||||
mv.visitInsn(IRETURN);
|
||||
mv.visitMaxs(0, 0);
|
||||
mv.visitEnd();
|
||||
}
|
||||
// static int test(I,11args)
|
||||
{
|
||||
mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "test", "(Lp/I;BCSIJLjava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)I", null, null);
|
||||
mv.visitCode();
|
||||
mv.visitLdcInsn(new Handle(Opcodes.H_INVOKEINTERFACE, "p/I", "m", "(BCSIJLjava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)I"));
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitVarInsn(ILOAD, 1);
|
||||
mv.visitVarInsn(ILOAD, 2);
|
||||
mv.visitVarInsn(ILOAD, 3);
|
||||
mv.visitVarInsn(ILOAD, 4);
|
||||
mv.visitVarInsn(LLOAD, 5);
|
||||
mv.visitVarInsn(ALOAD, 7);
|
||||
mv.visitVarInsn(ALOAD, 8);
|
||||
mv.visitVarInsn(ALOAD, 9);
|
||||
mv.visitVarInsn(ALOAD, 10);
|
||||
mv.visitVarInsn(ALOAD, 11);
|
||||
mv.visitVarInsn(ALOAD, 12);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle",
|
||||
"invokeExact", "(Lp/I;BCSIJLjava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)I");
|
||||
mv.visitInsn(IRETURN);
|
||||
mv.visitMaxs(0, 0);
|
||||
mv.visitEnd();
|
||||
}
|
||||
cw.visitEnd();
|
||||
return cw.toByteArray();
|
||||
}
|
||||
|
||||
private static void tryAndCheckThrown(
|
||||
List<Throwable> lt, byte[] dBytes, String what, Class<?> expected, String jar_name)
|
||||
throws Throwable {
|
||||
tryAndCheckThrown(lt, "p.D", dBytes, what, expected, jar_name);
|
||||
}
|
||||
|
||||
private static void tryAndCheckThrown(List<Throwable> lt, String d_name, byte[] dBytes, String what, Class<?> expected, String jar_name)
|
||||
throws Throwable {
|
||||
|
||||
System.out.println("Methodhandle invokeExact I.m() for instance of " + what);
|
||||
ByteClassLoader bcl1 = new ByteClassLoader(jar_name, readJarFiles, writeJarFiles);
|
||||
try {
|
||||
Object result = t.getMethod("test").invoke(null);
|
||||
System.out.println("Expected AbstractMethodError wrapped in InvocationTargetException, saw no exception");
|
||||
throw new Error("Missing expected exception");
|
||||
Class<?> d1 = bcl1.loadBytes(d_name, dBytes);
|
||||
Class<?> t1 = bcl1.loadBytes("p.T", bytesForT());
|
||||
invokeTest(t1, d1, expected, lt);
|
||||
} finally {
|
||||
// Not necessary for others -- all class files are written in this call.
|
||||
// (unless the VM crashes first).
|
||||
bcl1.close();
|
||||
}
|
||||
|
||||
System.out.println("Reflection invoke I.m() for instance of " + what);
|
||||
ByteClassLoader bcl3 = new ByteClassLoader(jar_name, readJarFiles, false);
|
||||
Class<?> d3 = bcl3.loadBytes(d_name, dBytes);
|
||||
Class<?> t3 = bcl3.loadClass("p.Treflect");
|
||||
invokeTest(t3, d3, expected, lt);
|
||||
|
||||
System.out.println("Bytecode invokeInterface I.m() for instance of " + what);
|
||||
ByteClassLoader bcl2 = new ByteClassLoader(jar_name, readJarFiles, false);
|
||||
Class<?> d2 = bcl2.loadBytes(d_name, dBytes);
|
||||
Class<?> t2 = bcl2.loadClass("p.Tdirect");
|
||||
badGoodBadGood(t2, d2, expected, lt);
|
||||
}
|
||||
|
||||
private static void invokeTest(Class<?> t, Class<?> d, Class<?> expected, List<Throwable> lt)
|
||||
throws Throwable {
|
||||
try {
|
||||
Method m = t.getMethod("test", p.I.class);
|
||||
Object o = d.newInstance();
|
||||
Object result = m.invoke(null, o);
|
||||
if (expected != null) {
|
||||
System.out.println("FAIL, Expected " + expected.getName()
|
||||
+ " wrapped in InvocationTargetException, but nothing was thrown");
|
||||
lt.add(new Error("Exception " + expected.getName() + " was not thrown"));
|
||||
} else {
|
||||
System.out.println("PASS, saw expected return.");
|
||||
}
|
||||
} catch (InvocationTargetException e) {
|
||||
Throwable th = e.getCause();
|
||||
if (th instanceof AbstractMethodError) {
|
||||
th.printStackTrace(System.out);
|
||||
System.out.println("PASS, saw expected exception (AbstractMethodError, wrapped in InvocationTargetException).");
|
||||
th.printStackTrace(System.out);
|
||||
if (expected != null) {
|
||||
if (expected.isInstance(th)) {
|
||||
System.out.println("PASS, saw expected exception (" + expected.getName() + ").");
|
||||
} else {
|
||||
System.out.println("FAIL, Expected " + expected.getName()
|
||||
+ " wrapped in InvocationTargetException, saw " + th);
|
||||
lt.add(th);
|
||||
}
|
||||
} else {
|
||||
System.out.println("Expected AbstractMethodError wrapped in InvocationTargetException, saw " + th);
|
||||
throw th;
|
||||
System.out.println("FAIL, expected no exception, saw " + th);
|
||||
lt.add(th);
|
||||
}
|
||||
}
|
||||
System.out.println();
|
||||
}
|
||||
|
||||
/* Many-arg versions of above */
|
||||
private static void tryAndCheckThrownMany(List<Throwable> lt, byte[] dBytes, String what, Class<?> expected)
|
||||
throws Throwable {
|
||||
|
||||
System.out.println("Methodhandle invokeExact I.m(11params) for instance of " + what);
|
||||
ByteClassLoader bcl1 = new ByteClassLoader("p.D", readJarFiles, false);
|
||||
try {
|
||||
Class<?> d1 = bcl1.loadBytes("p.D", dBytes);
|
||||
Class<?> t1 = bcl1.loadBytes("p.T", bytesForT());
|
||||
invokeTestMany(t1, d1, expected, lt);
|
||||
} finally {
|
||||
bcl1.close(); // Not necessary for others -- all class files are written in this call.
|
||||
}
|
||||
|
||||
{
|
||||
System.out.println("Bytecode invokeInterface I.m(11params) for instance of " + what);
|
||||
ByteClassLoader bcl2 = new ByteClassLoader("pD_m_pri_imp_pI", readJarFiles, false);
|
||||
Class<?> d2 = bcl2.loadBytes("p.D", dBytes);
|
||||
Class<?> t2 = bcl2.loadClass("p.Tdirect");
|
||||
badGoodBadGoodMany(t2, d2, expected, lt);
|
||||
|
||||
}
|
||||
{
|
||||
System.out.println("Reflection invokeInterface I.m(11params) for instance of " + what);
|
||||
ByteClassLoader bcl2 = new ByteClassLoader("pD_m_pri_imp_pI", readJarFiles, false);
|
||||
Class<?> d2 = bcl2.loadBytes("p.D", dBytes);
|
||||
Class<?> t2 = bcl2.loadClass("p.Treflect");
|
||||
invokeTestMany(t2, d2, expected, lt);
|
||||
}
|
||||
}
|
||||
|
||||
private static void invokeTestMany(Class<?> t, Class<?> d, Class<?> expected, List<Throwable> lt)
|
||||
throws Throwable {
|
||||
try {
|
||||
Method m = t.getMethod("test", p.I.class,
|
||||
Byte.TYPE, Character.TYPE, Short.TYPE, Integer.TYPE, Long.TYPE,
|
||||
Object.class, Object.class, Object.class,
|
||||
Object.class, Object.class, Object.class);
|
||||
Object o = d.newInstance();
|
||||
Byte b = 1;
|
||||
Character c = 2;
|
||||
Short s = 3;
|
||||
Integer i = 4;
|
||||
Long j = 5L;
|
||||
Object o1 = b;
|
||||
Object o2 = c;
|
||||
Object o3 = s;
|
||||
Object o4 = i;
|
||||
Object o5 = j;
|
||||
Object o6 = "6";
|
||||
|
||||
Object result = m.invoke(null, o, b, c, s, i, j,
|
||||
o1, o2, o3, o4, o5, o6);
|
||||
if (expected != null) {
|
||||
System.out.println("FAIL, Expected " + expected.getName()
|
||||
+ " wrapped in InvocationTargetException, but nothing was thrown");
|
||||
lt.add(new Error("Exception " + expected.getName()
|
||||
+ " was not thrown"));
|
||||
} else {
|
||||
System.out.println("PASS, saw expected return.");
|
||||
}
|
||||
} catch (InvocationTargetException e) {
|
||||
Throwable th = e.getCause();
|
||||
th.printStackTrace(System.out);
|
||||
if (expected != null) {
|
||||
if (expected.isInstance(th)) {
|
||||
System.out.println("PASS, saw expected exception ("
|
||||
+ expected.getName() + ").");
|
||||
} else {
|
||||
System.out.println("FAIL, Expected " + expected.getName()
|
||||
+ " wrapped in InvocationTargetException, saw " + th);
|
||||
lt.add(th);
|
||||
}
|
||||
} else {
|
||||
System.out.println("FAIL, expected no exception, saw " + th);
|
||||
lt.add(th);
|
||||
}
|
||||
}
|
||||
System.out.println();
|
||||
}
|
||||
|
||||
/**
|
||||
* This tests a peculiar idiom for tickling the bug on older VMs that lack
|
||||
* methodhandles. The bug (if not fixed) acts in the following way:
|
||||
*
|
||||
* When a broken receiver is passed to the first execution of an invokeinterface
|
||||
* bytecode, the illegal access is detected before the effects of resolution are
|
||||
* cached for later use, and so repeated calls with a broken receiver will always
|
||||
* throw the correct error.
|
||||
*
|
||||
* If, however, a good receiver is passed to the invokeinterface, the effects of
|
||||
* resolution will be successfully cached. A subsequent execution with a broken
|
||||
* receiver will reuse the cached information, skip the detailed resolution work,
|
||||
* and instead encounter a null pointer. By convention, that is the encoding for a
|
||||
* missing abstract method, and an AbstractMethodError is thrown -- not the expected
|
||||
* IllegalAccessError.
|
||||
*
|
||||
* @param t2 Test invocation class
|
||||
* @param d2 Test receiver class
|
||||
* @param expected expected exception type
|
||||
* @param lt list of unexpected throwables seen
|
||||
*/
|
||||
private static void badGoodBadGood(Class<?> t2, Class<?> d2, Class<?> expected, List<Throwable> lt)
|
||||
throws Throwable {
|
||||
System.out.println(" Error input 1st time");
|
||||
invokeTest(t2, d2, expected, lt);
|
||||
System.out.println(" Good input (instance of Dok)");
|
||||
invokeTest(t2, Dok.class, null, lt);
|
||||
System.out.println(" Error input 2nd time");
|
||||
invokeTest(t2, d2, expected, lt);
|
||||
System.out.println(" Good input (instance of Dok)");
|
||||
invokeTest(t2, Dok.class, null, lt);
|
||||
}
|
||||
|
||||
private static void badGoodBadGoodMany(Class<?> t2, Class<?> d2, Class<?> expected, List<Throwable> lt)
|
||||
throws Throwable {
|
||||
System.out.println(" Error input 1st time");
|
||||
invokeTestMany(t2, d2, expected, lt);
|
||||
System.out.println(" Good input (instance of Dok)");
|
||||
invokeTestMany(t2, Dok.class, null, lt);
|
||||
System.out.println(" Error input 2nd time");
|
||||
invokeTestMany(t2, d2, expected, lt);
|
||||
System.out.println(" Good input (instance of Dok)");
|
||||
invokeTestMany(t2, Dok.class, null, lt);
|
||||
}
|
||||
}
|
||||
|
@ -22,12 +22,14 @@
|
||||
*
|
||||
*/
|
||||
|
||||
package p;
|
||||
|
||||
/**
|
||||
* Test class -- implements I, which provides default for m, but this class
|
||||
* declares it abstract which (should) hide the interface default, and throw
|
||||
* an abstract method error if it is called (calling it requires bytecode hacking
|
||||
* or inconsistent compilation).
|
||||
* an abstract method error if called.
|
||||
*
|
||||
*/
|
||||
public abstract class C implements I {
|
||||
public abstract class C implements p.I {
|
||||
public abstract int m();
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 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 p;
|
||||
|
||||
/**
|
||||
* Test class -- implements I, extends E, both define m, so all should be well.
|
||||
*/
|
||||
public class Dok extends p.E {
|
||||
|
||||
}
|
38
hotspot/test/compiler/jsr292/methodHandleExceptions/p/E.java
Normal file
38
hotspot/test/compiler/jsr292/methodHandleExceptions/p/E.java
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 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 p;
|
||||
|
||||
/**
|
||||
* Test class -- implements I, which provides default for m, but this class
|
||||
* redeclares it so that all its non-overriding descendants should call its
|
||||
* method instead (with no error, assuming no descendant monkey business, which
|
||||
* of course is NOT usually the case in this test).
|
||||
*
|
||||
*/
|
||||
public abstract class E implements p.I {
|
||||
public int m() {
|
||||
return 2;
|
||||
}
|
||||
}
|
41
hotspot/test/compiler/jsr292/methodHandleExceptions/p/F.java
Normal file
41
hotspot/test/compiler/jsr292/methodHandleExceptions/p/F.java
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 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 p;
|
||||
|
||||
/**
|
||||
* Test class -- implements I, which provides default for m, but this class
|
||||
* redeclares it so that all its non-overriding descendants should call its
|
||||
* method instead (with no error, assuming no descendant monkey business, which
|
||||
* of course is NOT usually the case in this test).
|
||||
*
|
||||
* Note that m is final -- one form of monkey business is attempting to redefine
|
||||
* m.
|
||||
*
|
||||
*/
|
||||
public abstract class F implements p.I {
|
||||
final public int m() {
|
||||
return 2;
|
||||
}
|
||||
}
|
@ -22,6 +22,16 @@
|
||||
*
|
||||
*/
|
||||
|
||||
package p;
|
||||
|
||||
/**
|
||||
* Test interface I, provides default implementations for m() and m(11args).
|
||||
*/
|
||||
|
||||
public interface I {
|
||||
default public int m() { return 1; }
|
||||
default public int m(byte b, char c, short s, int i, long l,
|
||||
Object o1, Object o2, Object o3, Object o4, Object o5, Object o6) {
|
||||
return 2;
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 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 p;
|
||||
|
||||
/**
|
||||
* Invokes I.m directly using invokeInterface bytecodes.
|
||||
*/
|
||||
public class Tdirect {
|
||||
public static int test(p.I i) {
|
||||
int accum = 0;
|
||||
for (int j = 0; j < 100000; j++) {
|
||||
accum += i.m();
|
||||
}
|
||||
return accum;
|
||||
}
|
||||
|
||||
public static int test(p.I ii, byte b, char c, short s, int i, long l,
|
||||
Object o1, Object o2, Object o3, Object o4, Object o5, Object o6) {
|
||||
int accum = 0;
|
||||
for (int j = 0; j < 100000; j++) {
|
||||
accum += ii.m(b,c,s,i,l,o1,o2,o3,o4,o5,o6);
|
||||
}
|
||||
return accum;
|
||||
}
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 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 p;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* Invokes I.m using reflection.
|
||||
*/
|
||||
public class Treflect {
|
||||
|
||||
public static int test(p.I ii) throws Throwable {
|
||||
int accum = 0;
|
||||
Method m = p.I.class.getMethod("m");
|
||||
try {
|
||||
for (int j = 0; j < 100000; j++) {
|
||||
Object o = m.invoke(ii);
|
||||
accum += ((Integer) o).intValue();
|
||||
}
|
||||
} catch (InvocationTargetException ite) {
|
||||
throw ite.getCause();
|
||||
}
|
||||
return accum;
|
||||
}
|
||||
|
||||
public static int test(p.I ii, byte b, char c, short s, int i, long l,
|
||||
Object o1, Object o2, Object o3, Object o4, Object o5, Object o6)
|
||||
throws Throwable {
|
||||
Method m = p.I.class.getMethod("m", Byte.TYPE, Character.TYPE,
|
||||
Short.TYPE, Integer.TYPE, Long.TYPE,
|
||||
Object.class, Object.class, Object.class,
|
||||
Object.class, Object.class, Object.class);
|
||||
int accum = 0;
|
||||
try {
|
||||
for (int j = 0; j < 100000; j++) {
|
||||
Object o = m.invoke(ii, b, c, s, i, l, o1, o2, o3, o4, o5, o6);
|
||||
accum += ((Integer) o).intValue();
|
||||
}
|
||||
} catch (InvocationTargetException ite) {
|
||||
throw ite.getCause();
|
||||
}
|
||||
return accum;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user