Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Throw NoClassDefFoundError instead of TypeNotPresentException #610

Merged
merged 2 commits into from
Nov 24, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 11 additions & 40 deletions jcl/src/java.base/share/classes/java/lang/invoke/MethodHandle.java
Original file line number Diff line number Diff line change
Expand Up @@ -837,11 +837,7 @@ private static final MethodHandle resolveInvokeDynamic(long j9class, String name

Objects.requireNonNull(classObject);

try {
type = MethodType.fromMethodDescriptorString(methodDescriptor, access.getClassloader(classObject));
} catch (TypeNotPresentException e) {
throw throwNoClassDefFoundError(e);
}
type = MethodType.vmResolveFromMethodDescriptorString(methodDescriptor, access.getClassloader(classObject), null);
int bsmIndex = UNSAFE.getShort(bsmData);
int bsmArgCount = UNSAFE.getShort(bsmData + BSM_ARGUMENT_COUNT_OFFSET);
long bsmArgs = bsmData + BSM_ARGUMENTS_OFFSET;
Expand Down Expand Up @@ -916,11 +912,7 @@ private static final MethodHandle resolveInvokeDynamic(long j9class, String name
cpEntry = cp.getDoubleAt(index);
break;
case 13:
try {
cpEntry = getCPMethodTypeAt(internalRamClass, index);
} catch (TypeNotPresentException e) {
throw throwNoClassDefFoundError(e);
}
cpEntry = getCPMethodTypeAt(internalRamClass, index);
break;
case 14:
cpEntry = getCPMethodHandleAt(internalRamClass, index);
Expand Down Expand Up @@ -990,27 +982,6 @@ private static final MethodHandle resolveInvokeDynamic(long j9class, String name

return result;
}

/**
* Helper method to throw NoClassDefFoundError if the cause of TypeNotPresentException
* is ClassNotFoundException. Otherwise, re-throw TypeNotPresentException.
*
* @param an instance of TypeNotPresentException
*
* @return Throwable to prevent any fall through case
*
* @throws NoClassDefFoundError if the cause of TypeNotPresentException is
* ClassNotFoundException. Otherwise, re-throw TypeNotPresentException.
*/
private static Throwable throwNoClassDefFoundError(TypeNotPresentException e) {
Throwable cause = e.getCause();
if (cause instanceof ClassNotFoundException) {
NoClassDefFoundError noClassDefFoundError = new NoClassDefFoundError(cause.getMessage());
noClassDefFoundError.initCause(cause);
throw noClassDefFoundError;
}
throw e;
}

/**
* Retrieve the class name of the constant pool class element located at the specified
Expand All @@ -1025,7 +996,7 @@ private static Throwable throwNoClassDefFoundError(TypeNotPresentException e) {
*
* @throws NoClassDefFoundError with the cause set as ClassNotFoundException
*/
private static Throwable throwNoClassDefFoundError(Class<?> clazz, int index) {
private static final Throwable throwNoClassDefFoundError(Class<?> clazz, int index) {
String className = getCPClassNameAt(clazz, index);
NoClassDefFoundError noClassDefFoundError = new NoClassDefFoundError(className);
noClassDefFoundError.initCause(new ClassNotFoundException(className));
Expand Down Expand Up @@ -1105,7 +1076,7 @@ private static final MethodHandle sendResolveMethodHandle(
Class<?> referenceClazz,
String name,
String typeDescriptor,
ClassLoader loader) throws ClassNotFoundException, IllegalAccessException, NoSuchFieldException, NoSuchMethodException {
ClassLoader loader) throws Throwable {
MethodHandles.Lookup lookup = new MethodHandles.Lookup(currentClass, false);
MethodType type = null;

Expand All @@ -1119,19 +1090,19 @@ private static final MethodHandle sendResolveMethodHandle(
case 4: /* putStatic */
return lookup.findStaticSetter(referenceClazz, name, resolveFieldHandleHelper(typeDescriptor, loader));
case 5: /* invokeVirtual */
type = MethodType.fromMethodDescriptorString(typeDescriptor, loader);
type = MethodType.vmResolveFromMethodDescriptorString(typeDescriptor, loader, null);
return lookup.findVirtual(referenceClazz, name, type);
case 6: /* invokeStatic */
type = MethodType.fromMethodDescriptorString(typeDescriptor, loader);
type = MethodType.vmResolveFromMethodDescriptorString(typeDescriptor, loader, null);
return lookup.findStatic(referenceClazz, name, type);
case 7: /* invokeSpecial */
type = MethodType.fromMethodDescriptorString(typeDescriptor, loader);
type = MethodType.vmResolveFromMethodDescriptorString(typeDescriptor, loader, null);
return lookup.findSpecial(referenceClazz, name, type, currentClass);
case 8: /* newInvokeSpecial */
type = MethodType.fromMethodDescriptorString(typeDescriptor, loader);
type = MethodType.vmResolveFromMethodDescriptorString(typeDescriptor, loader, null);
return lookup.findConstructor(referenceClazz, type);
case 9: /* invokeInterface */
type = MethodType.fromMethodDescriptorString(typeDescriptor, loader);
type = MethodType.vmResolveFromMethodDescriptorString(typeDescriptor, loader, null);
return lookup.findVirtual(referenceClazz, name, type);
}
/* Can never happen */
Expand All @@ -1142,8 +1113,8 @@ private static final MethodHandle sendResolveMethodHandle(
* #fromMethodDescritorString(). The verifier checks to ensure that the typeDescriptor is
* a valid field descriptor so adding the "()V" around it is valid.
*/
private static final Class<?> resolveFieldHandleHelper(String typeDescriptor, ClassLoader loader) {
MethodType mt = MethodType.fromMethodDescriptorString("(" + typeDescriptor + ")V", loader); //$NON-NLS-1$ //$NON-NLS-2$
private static final Class<?> resolveFieldHandleHelper(String typeDescriptor, ClassLoader loader) throws Throwable {
MethodType mt = MethodType.vmResolveFromMethodDescriptorString("(" + typeDescriptor + ")V", loader, null); //$NON-NLS-1$ //$NON-NLS-2$
return mt.parameterType(0);
}

Expand Down
47 changes: 47 additions & 0 deletions jcl/src/java.base/share/classes/java/lang/invoke/MethodType.java
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,53 @@ private static final MethodType fromMethodDescriptorStringAppendArg(String metho
return methodType(returnType, types);
}

/**
* This helper calls MethodType.fromMethodDescriptorString(...) or
* MethodType.fromMethodDescriptorStringAppendArg(...) but throws
* NoClassDefFoundError instead of TypeNotPresentException during
* the VM resolve stage.
*
* @param methodDescriptor - the method descriptor string
* @param loader - the ClassLoader to be used
* @param appendArgumentType - an extra argument type
*
* @return a MethodType object representing the method descriptor string
*
* @throws IllegalArgumentException - if the string is not well-formed
* @throws NoClassDefFoundError - if a named type cannot be found
*/
static final MethodType vmResolveFromMethodDescriptorString(String methodDescriptor, ClassLoader loader, Class<?> appendArgumentType) throws Throwable {
try {
if (null == appendArgumentType) {
return MethodType.fromMethodDescriptorString(methodDescriptor, loader);
}
return MethodType.fromMethodDescriptorStringAppendArg(methodDescriptor, loader, appendArgumentType);
} catch (TypeNotPresentException e) {
throw throwNoClassDefFoundError(e);
}
}

/**
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you fix the formatting for the javadoc on this and the above method? The formatting is inconsistent between the two.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed.

* Helper method to throw NoClassDefFoundError if the cause of TypeNotPresentException
* is ClassNotFoundException. Otherwise, re-throw TypeNotPresentException.
*
* @param e - an instance of TypeNotPresentException
*
* @return a Throwable object to prevent any fall through case
*
* @throws NoClassDefFoundError - if the cause of e is ClassNotFoundException
* @throws TypeNotPresentException - if the cause of e is not ClassNotFoundException
*/
private static final Throwable throwNoClassDefFoundError(TypeNotPresentException e) {
Throwable cause = e.getCause();
if (cause instanceof ClassNotFoundException) {
NoClassDefFoundError noClassDefFoundError = new NoClassDefFoundError(cause.getMessage());
noClassDefFoundError.initCause(cause);
throw noClassDefFoundError;
}
throw e;
}

/*
* Convert the string from bytecode format to the format needed for ClassLoader#loadClass().
* Change all '/' to '.'.
Expand Down
3 changes: 1 addition & 2 deletions runtime/oti/vmconstantpool.xml
Original file line number Diff line number Diff line change
Expand Up @@ -333,8 +333,7 @@
<staticmethodref class="java/lang/J9VMInternals" name="threadCleanup" signature="(Ljava/lang/Thread;)V"/>
<staticmethodref class="java/lang/J9VMInternals" name="newInstanceImpl" signature="(Ljava/lang/Class;)Ljava/lang/Object;" flags="jit_newInstancePrototype"/>
<staticmethodref class="java/lang/J9VMInternals" name="formatNoSuchMethod" signature="(Ljava/lang/String;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/String;"/>
<staticmethodref class="java/lang/invoke/MethodType" name="fromMethodDescriptorString" signature="(Ljava/lang/String;Ljava/lang/ClassLoader;)Ljava/lang/invoke/MethodType;" flags="opt_methodHandle"/>
<staticmethodref class="java/lang/invoke/MethodType" name="fromMethodDescriptorStringAppendArg" signature="(Ljava/lang/String;Ljava/lang/ClassLoader;Ljava/lang/Class;)Ljava/lang/invoke/MethodType;" flags="opt_methodHandle"/>
<staticmethodref class="java/lang/invoke/MethodType" name="vmResolveFromMethodDescriptorString" signature="(Ljava/lang/String;Ljava/lang/ClassLoader;Ljava/lang/Class;)Ljava/lang/invoke/MethodType;" flags="opt_methodHandle"/>
<staticmethodref class="java/lang/invoke/MethodHandle" name="sendResolveMethodHandle" signature="(ILjava/lang/Class;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/ClassLoader;)Ljava/lang/invoke/MethodHandle;" flags="opt_methodHandle"/>
<staticmethodref class="java/lang/invoke/MethodHandle" name="resolveInvokeDynamic" signature="(JLjava/lang/String;Ljava/lang/String;J)Ljava/lang/invoke/MethodHandle;" flags="opt_methodHandle"/>
<staticmethodref class="java/lang/invoke/MethodHandle" name="invokeWithArgumentsHelper" signature="(Ljava/lang/invoke/MethodHandle;[Ljava/lang/Object;)Ljava/lang/Object;" flags="opt_methodHandle"/>
Expand Down
9 changes: 2 additions & 7 deletions runtime/vm/callin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -874,14 +874,9 @@ sendFromMethodDescriptorString(J9VMThread *currentThread, J9UTF8 *descriptor, J9
/* Run the method */
*--currentThread->sp = (UDATA)descriptorString;
*--currentThread->sp = (UDATA)classLoader->classLoaderObject;
*--currentThread->sp = (UDATA)J9VM_J9CLASS_TO_HEAPCLASS(appendArgType);
currentThread->returnValue = J9_BCLOOP_RUN_METHOD;
if (NULL == appendArgType) {
currentThread->returnValue2 = (UDATA)J9VMJAVALANGINVOKEMETHODTYPE_FROMMETHODDESCRIPTORSTRING_METHOD(vm);
} else {
/* If an appendArgType has been provided, push it on the stack and call a different MethodType factory method. */
*--currentThread->sp = (UDATA)J9VM_J9CLASS_TO_HEAPCLASS(appendArgType);
currentThread->returnValue2 = (UDATA)J9VMJAVALANGINVOKEMETHODTYPE_FROMMETHODDESCRIPTORSTRINGAPPENDARG_METHOD(vm);
}
currentThread->returnValue2 = (UDATA)J9VMJAVALANGINVOKEMETHODTYPE_VMRESOLVEFROMMETHODDESCRIPTORSTRING_METHOD(vm);
c_cInterpreter(currentThread);
}
restoreCallInFrame(currentThread);
Expand Down
23 changes: 5 additions & 18 deletions test/Jsr292/src/com/ibm/j9/jsr292/indyn/IndyTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -333,27 +333,14 @@ public void test_indyn_ldc_BootstrapMethod_type() {
}
}

//Negative test : Creating an invalid MethodType using LDC
//Negative test : Creating a MethodType with a non-existent class using LDC
@Test(groups = { "level.extended" })
public void test_indyn_ldc_invalid_type() {

boolean typeNotPresentExceptionThrown = false;

public void test_indyn_ldc_non_existent_class_methodtype() {
try {
MethodType mtToString = com.ibm.j9.jsr292.indyn.GenIndyn.ldc_invalid_type();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mtToString is not used, can it be removed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should keep it since it tells what is being returned.

} catch ( java.lang.TypeNotPresentException e ) {
typeNotPresentExceptionThrown = true;
}

//Call it again
try {
MethodType mtToString = com.ibm.j9.jsr292.indyn.GenIndyn.ldc_invalid_type();
} catch ( java.lang.TypeNotPresentException e ) {
typeNotPresentExceptionThrown = true;
}

if ( typeNotPresentExceptionThrown == false ) {
Assert.fail("TypeNotPresentException not thrown when invalid type descriptor is used to create MethodType via LDC");
Assert.fail("NoClassDefFoundError not thrown when non-existent class is used to create MethodType via LDC");
} catch (NoClassDefFoundError e) {
/* Expected behavior */
}
}

Expand Down