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

[lworld] small reflection implementation clean up #93

Closed
wants to merge 3 commits into from
Closed
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -55,7 +55,7 @@
* @see LambdaMetafactory
*/
/* package */ final class InnerClassLambdaMetafactory extends AbstractValidatingLambdaMetafactory {
private static final int CLASSFILE_VERSION = 52;
private static final int CLASSFILE_VERSION = V15;
private static final String METHOD_DESCRIPTOR_VOID = Type.getMethodDescriptor(Type.VOID_TYPE);
private static final String JAVA_LANG_OBJECT = "java/lang/Object";
private static final String NAME_CTOR = "<init>";
@@ -177,7 +177,8 @@ public static void setAccessible(AccessibleObject[] array, boolean flag) {
* to the caller's module. </p>
*
* <p> This method cannot be used to enable {@linkplain Field#set <em>write</em>}
* access to a final field declared in a {@linkplain Class#isHidden() hidden class},
* access to a final field declared in a {@linkplain Class#isHidden() hidden class}
* and an {@linkplain Class#isInlineClass() inline class},
* since such fields are not modifiable. The {@code accessible} flag when
* {@code true} suppresses Java language access control checks to only
* enable {@linkplain Field#get <em>read</em>} access to such fields.
@@ -309,19 +310,6 @@ private boolean checkCanSetAccessible(Class<?> caller,
modifiers = ((Field) this).getModifiers();
}

// Do not allow suppression of access check for inline class's field
if (declaringClass.isInlineClass() &&
this instanceof Field
&& Modifier.isFinal(modifiers)) {
if (throwExceptionIfDenied) {
String msg = "Unable to make field accessible of inline class "
+ declaringClass.getName();
throw new InaccessibleObjectException(msg);
} else {
return false;
}
}

Module callerModule = caller.getModule();
Module declaringModule = declaringClass.getModule();

@@ -166,10 +166,6 @@ Field copy() {
public void setAccessible(boolean flag) {
AccessibleObject.checkPermission();

if (clazz.isInlineClass()) {
throw new InaccessibleObjectException("cannot make a field accessible of inline class "
+ clazz.getName());
}
if (flag) {
checkCanSetAccessible(Reflection.getCallerClass());
}
@@ -420,8 +420,7 @@ protected boolean isPrivate() {
return "[" + getClassName(c.getComponentType(), true);
} else {
if (addPrefixAndSuffixForNonPrimitiveTypes) {
final String desc = (c.isInlineClass() ? 'Q' : 'L') + c.getName() + ";";
return internalize(desc);
return c.descriptorString();
} else {
return internalize(c.getName());
}
@@ -81,7 +81,7 @@ public void set(Object obj, Object value)
if (isFlattened()) {
unsafe.putValue(obj, fieldOffset, field.getType(), value);
} else {
unsafe.putReference(obj, fieldOffset, value);
unsafe.putReference(obj, fieldOffset, value);
}
}

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2020, 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
@@ -25,18 +25,20 @@
/*
* @test
* @summary Test reflection of constructors for inline classes
* @run main/othervm InlineConstructorTest
* @run testng/othervm InlineConstructorTest
*/

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InaccessibleObjectException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.Set;
import java.util.stream.Collectors;

import org.testng.annotations.Test;
import static org.testng.Assert.*;

public class InlineConstructorTest {

// Target test class
@@ -52,42 +54,32 @@ public SimpleInline(int x) {
}
}

private final Class<?> c;

public static void main(String... args) throws Exception {
testSimpleInlineClass();
}

static void testSimpleInlineClass() throws Exception {
InlineConstructorTest test = new InlineConstructorTest(SimpleInline.class);
test.constructor();
test.constructors("public InlineConstructorTest$SimpleInline(int)",
"InlineConstructorTest$SimpleInline()");
test.setAccessible();
test.trySetAccessible();
test.initFactoryNotMethods();
}
static final Class<?> INLINE_TYPE = SimpleInline.class;

InlineConstructorTest(Class<?> type) throws Exception {
String cn = type.getName();
this.c = Class.forName(cn);
@Test
public static void testInlineClassConstructor() throws Exception {
String cn = INLINE_TYPE.getName();
Class<?> c = Class.forName(cn);

assertTrue(c.isInlineClass());
assertEquals(c, type);
assertEquals(c, INLINE_TYPE);
}

void constructor() throws Exception {
Constructor<?> ctor = c.getDeclaredConstructor();
@Test
public static void constructor() throws Exception {
Constructor<?> ctor = INLINE_TYPE.getDeclaredConstructor();
Object o = ctor.newInstance();
assertEquals(o.getClass(), c);
assertEquals(o.getClass(), INLINE_TYPE);
}

// Check that the class has the expected Constructors
void constructors(String... expected) throws Exception {
Constructor<? extends Object>[] cons = c.getDeclaredConstructors();
Set<String> actualSig =
Arrays.stream(cons).map(Constructor::toString).collect(Collectors.toSet());
Set<String> expectedSig = Set.of(expected);
@Test
public static void constructors() throws Exception {
Set<String> expectedSig = Set.of("public InlineConstructorTest$SimpleInline(int)",
"InlineConstructorTest$SimpleInline()");
Constructor<? extends Object>[] cons = INLINE_TYPE.getDeclaredConstructors();
Set<String> actualSig = Arrays.stream(cons).map(Constructor::toString)
.collect(Collectors.toSet());
boolean ok = expectedSig.equals(actualSig);
if (!ok) {
System.out.printf("expected: %s%n", expectedSig);
@@ -96,53 +88,43 @@ void constructors(String... expected) throws Exception {
}
}

// Check that the constructor can be set accessible and that the field x can not
void setAccessible() throws Exception {
Constructor<?> ctor = c.getDeclaredConstructor();
// Check that the constructor and field can be set accessible
@Test
public static void setAccessible() throws Exception {
Constructor<?> ctor = INLINE_TYPE.getDeclaredConstructor();
ctor.setAccessible(true);
Field field = c.getField("x");
try {
field.setAccessible(true);
throw new RuntimeException("InaccessibleObjectException not thrown");
} catch (InaccessibleObjectException e) {
// IOE is expected
}

Field field = INLINE_TYPE.getField("x");
field.setAccessible(true);
}

// Check that the constructor can be set accessible and that the field x can not
void trySetAccessible() throws Exception {
Constructor<?> ctor = c.getDeclaredConstructor();
// Check that the constructor and field can be set accessible
@Test
public static void trySetAccessible() throws Exception {
Constructor<?> ctor = INLINE_TYPE.getDeclaredConstructor();
assertTrue(ctor.trySetAccessible());
Field field = c.getField("x");
if (field.trySetAccessible()) {
throw new RuntimeException("trySetAccessible should not succeed");
}

Field field = INLINE_TYPE.getField("x");
assertTrue(field.trySetAccessible());
}

// Check that the final field cannot be modified
@Test(expectedExceptions = IllegalAccessException.class)
public static void setFinalField() throws Exception {
Field field = INLINE_TYPE.getField("x");
field.setAccessible(true);
field.setInt(new SimpleInline(100), 200);
}


// Check that the class does not have a static method with the name <init>
void initFactoryNotMethods() {
Method[] methods = c.getDeclaredMethods();
@Test
public static void initFactoryNotMethods() {
Method[] methods = INLINE_TYPE.getDeclaredMethods();
for (Method m : methods) {
if (Modifier.isStatic(m.getModifiers())) {
assertFalse(m.getName().equals("<init>"));
}
}
}

static void assertEquals(Object o1, Object o2) {
if (o1 == o2 || o1.equals(o2))
return;

throw new AssertionError(o1 + " != " + o2);
}

static void assertTrue(boolean value) {
if (!value)
throw new AssertionError("expected true");
}

static void assertFalse(boolean value) {
if (value)
throw new AssertionError("expected false");
}
}
@@ -31,7 +31,6 @@
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InaccessibleObjectException;
import java.lang.reflect.Method;

import org.testng.annotations.Test;
@@ -192,13 +191,8 @@ void constructor() throws Exception {

void staticField() throws Exception {
Field f = c.getDeclaredField("STATIC_FIELD");
if (f.trySetAccessible()) {
throw new RuntimeException("trySetAccessible should not succeed");
}
try {
f.setAccessible(true);
throw new RuntimeException("IllegalAccessException not thrown");
} catch (InaccessibleObjectException e) { }
f.trySetAccessible();
assertTrue(f.isAccessible());
}

void checkField(String source, String name, Class<?> type) throws Exception {