提交 a28ec875 编写于 作者: D drchase

8016839: JSR292: AME instead of IAE when calling a method

Summary: Catch missing-because-illegal case for itable entries and use an exception-throwing method instead of null.
Reviewed-by: acorn, jrose, coleenp
上级 683f8520
......@@ -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
......
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) {
}
}
}
}
......@@ -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();
}
......@@ -21,7 +21,11 @@
* questions.
*
*/
package p;
/**
* Test class -- implements I, extends E, both define m, so all should be well.
*/
public class Dok extends p.E {
public interface I {
default public int m() { return 1; }
}
/*
* 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;
}
}
/*
* 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;
}
}
/*
* 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 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;
}
}
/*
* 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;
}
}
/*
* 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;
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册