Skip to content

Commit

Permalink
Merge pull request #4157 from theresa-m/jep334_class
Browse files Browse the repository at this point in the history
Methods and tests for jep334 Class
  • Loading branch information
DanHeidinga authored Feb 22, 2019
2 parents 525ba18 + e416518 commit 1440bcf
Show file tree
Hide file tree
Showing 7 changed files with 285 additions and 6 deletions.
65 changes: 61 additions & 4 deletions jcl/src/java.base/share/classes/java/lang/Class.java
Original file line number Diff line number Diff line change
Expand Up @@ -4561,20 +4561,77 @@ public Class<?>[] getNestMembers() throws LinkageError, SecurityException {
/*[ENDIF] Java11 */

/*[IF Java12]*/
/**
* Create class of an array. The component type will be this Class instance.
*
* @return array class where the component type is this Class instance
*/
public Class<?> arrayType() {
throw new UnsupportedOperationException("Stub for Java 12 compilation (Jep334)");
if (this == void.class) {
throw new IllegalArgumentException();
}
return arrayTypeImpl();
}

private native Class<?> arrayTypeImpl();

/**
* Answers a Class object which represents the receiver's component type if the receiver
* represents an array type. The component type of an array type is the type of the elements
* of the array.
*
* @return the component type of the receiver. Returns null if the receiver does
* not represent an array.
*/
public Class<?> componentType() {
throw new UnsupportedOperationException("Stub for Java 12 compilation (Jep334)");
return getComponentType();
}

/**
* Returns the nominal descriptor of this Class instance, or an empty Optional
* if construction is not possible.
*
* @return Optional with a nominal descriptor of Class instance
*/
public Optional<ClassDesc> describeConstable() {
throw new UnsupportedOperationException("Stub for Java 12 compilation (Jep334)");
ClassDesc classDescriptor = ClassDesc.ofDescriptor(this.descriptorString());
return Optional.of(classDescriptor);
}

/**
* Return field descriptor of Class instance.
*
* @return field descriptor of Class instance
*/
public String descriptorString() {
throw new UnsupportedOperationException("Stub for Java 12 compilation (Jep334)");
/* see MethodType.getBytecodeStringName */

if (this.isPrimitive()) {
if (this == int.class) {
return "I"; //$NON-NLS-1$
} else if (this == long.class) {
return "J"; //$NON-NLS-1$
} else if (this == byte.class) {
return "B"; //$NON-NLS-1$
} else if (this == boolean.class) {
return "Z"; //$NON-NLS-1$
} else if (this == void.class) {
return "V"; //$NON-NLS-1$
} else if (this == char.class) {
return "C"; //$NON-NLS-1$
} else if (this == double.class) {
return "D"; //$NON-NLS-1$
} else if (this == float.class) {
return "F"; //$NON-NLS-1$
} else if (this == short.class) {
return "S"; //$NON-NLS-1$
}
}
String name = this.getName().replace('.', '/');
if (this.isArray()) {
return name;
}
return "L"+ name + ";"; //$NON-NLS-1$ //$NON-NLS-2$
}
/*[ENDIF] Java12 */
}
3 changes: 2 additions & 1 deletion runtime/oti/VMHelpers.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 1991, 2018 IBM Corp. and others
* Copyright (c) 1991, 2019 IBM Corp. and others
*
* This program and the accompanying materials are made available under
* the terms of the Eclipse Public License 2.0 which accompanies this
Expand Down Expand Up @@ -165,6 +165,7 @@ typedef enum {
J9_BCLOOP_SEND_TARGET_VARHANDLE,
J9_BCLOOP_SEND_TARGET_INL_THREAD_ON_SPIN_WAIT,
J9_BCLOOP_SEND_TARGET_OUT_OF_LINE_INL,
J9_BCLOOP_SEND_TARGET_CLASS_ARRAY_TYPE_IMPL,
} VM_SendTarget;

typedef enum {
Expand Down
23 changes: 23 additions & 0 deletions runtime/vm/BytecodeInterpreter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2721,6 +2721,26 @@ done:;
return EXECUTE_BYTECODE;
}

/* java.lang.Class: private native Class<?> arrayTypeImpl(); */
VMINLINE VM_BytecodeAction
inlClassArrayTypeImpl(REGISTER_ARGS_LIST)
{
VM_BytecodeAction rc = EXECUTE_BYTECODE;
J9Class *componentClazz = J9VM_J9CLASS_FROM_HEAPCLASS(_currentThread, *(j9object_t*)_sp);
J9Class *arrayClazz = componentClazz->arrayClass;
if (NULL == arrayClazz) {
arrayClazz = internalCreateArrayClass(_currentThread,
(J9ROMArrayClass *) J9ROMIMAGEHEADER_FIRSTCLASS(_currentThread->javaVM->arrayROMClasses),
componentClazz);
}
if (NULL == arrayClazz) {
rc = GOTO_THROW_CURRENT_EXCEPTION;
} else {
returnObjectFromINL(REGISTER_ARGS, J9VM_J9CLASS_TO_HEAPCLASS(arrayClazz), 1);
}
return rc;
}

/* java.lang.Class: private native String getSimpleNameImpl(); */
VMINLINE VM_BytecodeAction
inlClassGetSimpleNameImpl(REGISTER_ARGS_LIST)
Expand Down Expand Up @@ -8718,6 +8738,7 @@ done:;
JUMP_TABLE_ENTRY(J9_BCLOOP_SEND_TARGET_VARHANDLE),
JUMP_TABLE_ENTRY(J9_BCLOOP_SEND_TARGET_INL_THREAD_ON_SPIN_WAIT),
JUMP_TABLE_ENTRY(J9_BCLOOP_SEND_TARGET_OUT_OF_LINE_INL),
JUMP_TABLE_ENTRY(J9_BCLOOP_SEND_TARGET_CLASS_ARRAY_TYPE_IMPL),
};
#endif /* !defined(USE_COMPUTED_GOTO) */

Expand Down Expand Up @@ -9277,6 +9298,8 @@ runMethod: {
PERFORM_ACTION(inlThreadOnSpinWait(REGISTER_ARGS));
JUMP_TARGET(J9_BCLOOP_SEND_TARGET_OUT_OF_LINE_INL):
PERFORM_ACTION(outOfLineINL(REGISTER_ARGS));
JUMP_TARGET(J9_BCLOOP_SEND_TARGET_CLASS_ARRAY_TYPE_IMPL):
PERFORM_ACTION(inlClassArrayTypeImpl(REGISTER_ARGS));
#if !defined(USE_COMPUTED_GOTO)
default:
Assert_VM_unreachable();
Expand Down
22 changes: 21 additions & 1 deletion runtime/vm/FastJNI_java_lang_Class.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2001, 2018 IBM Corp. and others
* Copyright (c) 2001, 2019 IBM Corp. and others
*
* This program and the accompanying materials are made available under
* the terms of the Eclipse Public License 2.0 which accompanies this
Expand Down Expand Up @@ -180,6 +180,24 @@ Fast_java_lang_Class_getModifiersImpl(J9VMThread *currentThread, j9object_t rece
return (jint)modifiers;
}

/* java.lang.Class: private native Class<?> arrayTypeImpl(); */
j9object_t JNICALL
Fast_java_lang_Class_arrayTypeImpl(J9VMThread *currentThread, j9object_t receiverObject)
{
j9object_t arrayObject = NULL;
J9Class *componentClazz = J9VM_J9CLASS_FROM_HEAPCLASS(currentThread, receiverObject);
J9Class *arrayClazz = componentClazz->arrayClass;
if (NULL == arrayClazz) {
arrayClazz = internalCreateArrayClass(currentThread,
(J9ROMArrayClass *) J9ROMIMAGEHEADER_FIRSTCLASS(currentThread->javaVM->arrayROMClasses),
componentClazz);
}
if (NULL != arrayClazz) {
arrayObject = J9VM_J9CLASS_TO_HEAPCLASS(arrayClazz);
}
return arrayObject;
}

/* java.lang.Class: public native Class<?> getComponentType(); */
j9object_t JNICALL
Fast_java_lang_Class_getComponentType(J9VMThread *currentThread, j9object_t receiverObject)
Expand Down Expand Up @@ -212,6 +230,8 @@ J9_FAST_JNI_METHOD_TABLE(java_lang_Class)
J9_FAST_JNI_METHOD("getComponentType", "()Ljava/lang/Class;", Fast_java_lang_Class_getComponentType,
J9_FAST_JNI_RETAIN_VM_ACCESS | J9_FAST_JNI_NOT_GC_POINT | J9_FAST_JNI_NO_NATIVE_METHOD_FRAME | J9_FAST_JNI_NO_EXCEPTION_THROW |
J9_FAST_JNI_NO_SPECIAL_TEAR_DOWN | J9_FAST_JNI_DO_NOT_WRAP_OBJECTS)
J9_FAST_JNI_METHOD("arrayTypeImpl", "()Ljava/lang/Class;", Fast_java_lang_Class_arrayTypeImpl,
J9_FAST_JNI_RETAIN_VM_ACCESS | J9_FAST_JNI_DO_NOT_WRAP_OBJECTS)
J9_FAST_JNI_METHOD_TABLE_END

}
1 change: 1 addition & 0 deletions runtime/vm/bindnatv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ static inlMapping mappings[] = {
{ "Java_java_lang_Class_isPrimitive__", J9_BCLOOP_SEND_TARGET_INL_CLASS_IS_PRIMITIVE },
{ "Java_java_lang_Class_getModifiersImpl__", J9_BCLOOP_SEND_TARGET_INL_CLASS_GET_MODIFIERS_IMPL },
{ "Java_java_lang_Class_getComponentType__", J9_BCLOOP_SEND_TARGET_INL_CLASS_GET_COMPONENT_TYPE },
{ "Java_java_lang_Class_arrayTypeImpl__", J9_BCLOOP_SEND_TARGET_CLASS_ARRAY_TYPE_IMPL },
{ "Java_java_lang_System_arraycopy__Ljava_lang_Object_2ILjava_lang_Object_2II", J9_BCLOOP_SEND_TARGET_INL_SYSTEM_ARRAYCOPY },
{ "Java_java_lang_System_currentTimeMillis__", J9_BCLOOP_SEND_TARGET_INL_SYSTEM_CURRENT_TIME_MILLIS },
{ "Java_java_lang_System_nanoTime__", J9_BCLOOP_SEND_TARGET_INL_SYSTEM_NANO_TIME },
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
/*******************************************************************************
* Copyright (c) 2018, 2019 IBM Corp. and others
*
* This program and the accompanying materials are made available under
* the terms of the Eclipse Public License 2.0 which accompanies this
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/
* or the Apache License, Version 2.0 which accompanies this distribution and
* is available at https://www.apache.org/licenses/LICENSE-2.0.
*
* This Source Code may also be made available under the following
* Secondary Licenses when the conditions for such availability set
* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
* General Public License, version 2 with the GNU Classpath
* Exception [1] and GNU General Public License, version 2 with the
* OpenJDK Assembly Exception [2].
*
* [1] https://www.gnu.org/software/classpath/license.html
* [2] http://openjdk.java.net/legal/assembly-exception.html
*
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception
*******************************************************************************/
package org.openj9.test.java_lang;

import java.lang.constant.ClassDesc;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
import java.util.Optional;

import org.testng.Assert;
import org.testng.annotations.Test;
import org.testng.log4testng.Logger;

/**
* This test Java.lang.Class API added in Java 12 and later version.
*
* new methods:
* - describeConstable()
* - descriptorString()
* - arrayType()
* - componentType(): wrapper for Class.getComponentType(), not tested
*/
public class Test_Class {
public static Logger logger = Logger.getLogger(Test_Class.class);

Object[][] primitiveTest = {
{ boolean.class, "Z" },
{ byte.class, "B" },
{ char.class, "C" },
{ short.class, "S" },
{ int.class, "I" },
{ float.class, "F" },
{ double.class, "D" },
{ long.class, "J" },
{ void.class, "V" }
};

/* descriptor strings */
String objectResult = "Ljava/lang/Object;";
String arrayResult = "[D";
String arrayResult2 = "[[[D";

/* test classes */
Class<?> objectTest = new Object().getClass();
Class<?> arrayTest = new double[0].getClass();
Class<?> arrayTest2 = new double[0][][].getClass();
Runnable lambdaExp = () -> System.out.println("test");
Class<?> lambdaExpTest = lambdaExp.getClass();

/*
* Test Java 12 API Class.descriptorString()
*/
@Test(groups = { "level.sanity" })
public void testClassDescriptorString() {
/* primitive type test */
for (Object[] prim : primitiveTest) {
logger.debug("testClassDescriptorString: Primitive test result is: " + ((Class<?>)prim[0]).descriptorString() + " expected: " + prim[1]);
Assert.assertTrue(((Class<?>)prim[0]).descriptorString().equals(prim[1]));
}

/* ObjectType test */
logger.debug("testClassDescriptorString: Object test result is: " + objectTest.descriptorString() + " expected: " + objectResult);
Assert.assertTrue(objectTest.descriptorString().equals(objectResult));

/* ArrayType test */
logger.debug("testClassDescriptorString: Array test result is: " + arrayTest.descriptorString() + " expected: " + arrayResult);
Assert.assertTrue(arrayTest.descriptorString().equals(arrayResult));

/* ArrayType test 2 */
logger.debug("testClassDescriptorString: Array test 2 result is: " + arrayTest2.descriptorString() + " expected: " + arrayResult2);
Assert.assertTrue(arrayTest2.descriptorString().equals(arrayResult2));

/*
* Lambda expression test. DescriptorString value will be different in each run.
* Verify that no error is thrown.
*/
logger.debug("testClassDescriptorString: Lambda test result is: " + lambdaExpTest.descriptorString());
}

/*
* Test Java 12 API Class.describeConstable()
*/
@Test(groups = { "level.sanity" })
public void testClassDescribeConstable() throws Throwable {
for (Object[] prim : primitiveTest) {
describeConstableTestGeneral("testClassDescribeConstable (primitive " + prim[1] + ")", (Class<?>)prim[0]);
}
describeConstableTestGeneral("testClassDescribeConstable (object)", objectTest);
describeConstableTestGeneral("testClassDescribeConstable (array)", arrayTest);
describeConstableTestGeneral("testClassDescribeConstable (array 2)", arrayTest2);
describeConstableTestLambda("testClassDescribeConstable (lambda expression)");
}

private void describeConstableTestGeneral(String testName, Class<?> testClass) throws Throwable {
Optional<ClassDesc> optionalDesc = testClass.describeConstable();
ClassDesc desc = optionalDesc.orElseThrow();

/*
* verify that descriptor can be resolved. Otherwise exception will be thrown.
*/
Class<?> resolvedClass = (Class<?>)desc.resolveConstantDesc(MethodHandles.lookup());

String originalDescriptor = testClass.descriptorString();
String newDescriptor = resolvedClass.descriptorString();
logger.debug(testName + ": Descriptor of original class is: " + originalDescriptor + " descriptor of ClassDesc is: " + newDescriptor);
Assert.assertTrue(testClass.equals(resolvedClass));
}

/*
* seperate test case for lambda expression because resolveConstantDesc is
* expected to fail.
*/
private void describeConstableTestLambda(String testName) {
Optional<ClassDesc> optionalDesc = lambdaExpTest.describeConstable();
ClassDesc desc = optionalDesc.orElseThrow();

/*
* verify that descriptor can be resolved. Otherwise exception will be thrown.
*/
try {
Class<?> resolvedClass = (Class<?>)desc.resolveConstantDesc(MethodHandles.lookup());
Assert.fail(testName + " : resolveConstantDesc did not throw an error.");
} catch (Throwable e) {
/* resolveConstantDesc is expected to fail */
logger.debug(testName + ": exception thrown for resolveConstantDesc was " + e.toString());
}
}

/*
* Test Java 12 API Class.arrayType()
*/
@Test(groups = { "level.sanity" })
public void testClassArrayType() throws Throwable {
for (Object[] prim : primitiveTest) {
if ((Class<?>)prim[0] == void.class) {
/* test is expected to throw IllegalArgumentException */
try {
arrayTypeTestGeneral("testClassArrayType (primitive) this test should throw IllegalArgumentException", (Class<?>)prim[0], (String)prim[1]);
Assert.fail();
} catch(IllegalArgumentException e) {
/* test passed */
}
} else {
arrayTypeTestGeneral("testClassArrayType (primitive)", (Class<?>)prim[0], (String)prim[1]);
}
}
arrayTypeTestGeneral("testClassArrayType (object)", objectTest, objectResult);
arrayTypeTestGeneral("testClassArrayType (embedded array)", arrayTest, arrayResult);
}

private void arrayTypeTestGeneral(String testName, Class<?> testClass, String result) throws Throwable {
Class<?> array = testClass.arrayType();
String arrayString = array.descriptorString();
logger.debug(testName + ": Descriptor of component is: " + result + " descriptor of array is: " + arrayString);
Assert.assertTrue(arrayString.equals("[" + result));
}
}
1 change: 1 addition & 0 deletions test/functional/Java12andUp/testng.xml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
<test name="Jep334Tests">
<classes>
<class name="org.openj9.test.java_lang.Test_String" />
<class name="org.openj9.test.java_lang.Test_Class" />
</classes>
</test>

Expand Down

0 comments on commit 1440bcf

Please sign in to comment.