Skip to content

Commit

Permalink
8296967: [JVMCI] rationalize relationship between getCodeSize and get…
Browse files Browse the repository at this point in the history
…Code in ResolvedJavaMethod

Reviewed-by: adinn
Backport-of: 37848a9ca2ab3021e7b3b2e112bab4631fbe1d99
  • Loading branch information
jerboaa committed Nov 25, 2022
1 parent b4a4f6a commit b464cc2
Show file tree
Hide file tree
Showing 8 changed files with 271 additions and 78 deletions.
6 changes: 0 additions & 6 deletions src/hotspot/share/jvmci/jvmciCompilerToVM.cpp
Expand Up @@ -1793,9 +1793,6 @@ C2V_VMENTRY_NULL(jobjectArray, getDeclaredConstructors, (JNIEnv* env, jobject, j
}

InstanceKlass* iklass = InstanceKlass::cast(klass);
// Ensure class is linked
iklass->link_class(CHECK_NULL);

GrowableArray<Method*> constructors_array;
for (int i = 0; i < iklass->methods()->length(); i++) {
Method* m = iklass->methods()->at(i);
Expand Down Expand Up @@ -1823,9 +1820,6 @@ C2V_VMENTRY_NULL(jobjectArray, getDeclaredMethods, (JNIEnv* env, jobject, jobjec
}

InstanceKlass* iklass = InstanceKlass::cast(klass);
// Ensure class is linked
iklass->link_class(CHECK_NULL);

GrowableArray<Method*> methods_array;
for (int i = 0; i < iklass->methods()->length(); i++) {
Method* m = iklass->methods()->at(i);
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2022, 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
Expand Down Expand Up @@ -45,6 +45,9 @@ final class HotSpotProfilingInfo implements ProfilingInfo {
HotSpotProfilingInfo(HotSpotMethodData methodData, HotSpotResolvedJavaMethod method, boolean includeNormal, boolean includeOSR) {
this.methodData = methodData;
this.method = method;
if (!method.getDeclaringClass().isLinked()) {
throw new IllegalArgumentException(method.format("%H.%n(%p) must be linked"));
}
this.includeNormal = includeNormal;
this.includeOSR = includeOSR;
this.isMature = methodData.isProfileMature();
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2022, 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
Expand Down Expand Up @@ -258,7 +258,11 @@ public byte[] getCode() {

@Override
public int getCodeSize() {
return UNSAFE.getChar(getConstMethod() + config().constMethodCodeSizeOffset);
int codeSize = UNSAFE.getChar(getConstMethod() + config().constMethodCodeSizeOffset);
if (codeSize > 0 && !getDeclaringClass().isLinked()) {
return -1;
}
return codeSize;
}

@Override
Expand Down
Expand Up @@ -995,11 +995,28 @@ public HotSpotResolvedObjectType getEnclosingType() {

@Override
public ResolvedJavaMethod[] getDeclaredConstructors() {
link();
return runtime().compilerToVm.getDeclaredConstructors(this);
}

@Override
public ResolvedJavaMethod[] getDeclaredConstructors(boolean forceLink) {
if (forceLink) {
link();
}
return runtime().compilerToVm.getDeclaredConstructors(this);
}

@Override
public ResolvedJavaMethod[] getDeclaredMethods() {
return getDeclaredMethods(true);
}

@Override
public ResolvedJavaMethod[] getDeclaredMethods(boolean forceLink) {
if (forceLink) {
link();
}
return runtime().compilerToVm.getDeclaredMethods(this);
}

Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2009, 2022, 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
Expand Down Expand Up @@ -36,24 +36,26 @@
public interface ResolvedJavaMethod extends JavaMethod, InvokeTarget, ModifiersProvider, AnnotatedElement {

/**
* Returns the bytecode of this method, if the method has code. The returned byte array does not
* contain breakpoints or non-Java bytecodes. This may return null if the
* {@linkplain #getDeclaringClass() declaring class} is not
* {@linkplain ResolvedJavaType#isLinked() linked}.
* Returns the method's bytecode. The returned bytecode does not contain breakpoints or non-Java
* bytecodes. This will return {@code null} if {@link #getCodeSize()} returns {@code <= 0} or if
* {@link #hasBytecodes()} returns {@code false}.
*
* The contained constant pool indices may not be the ones found in the original class file but
* The contained constant pool indexes may not be the ones found in the original class file but
* they can be used with the JVMCI API (e.g. methods in {@link ConstantPool}).
*
* @return the bytecode of the method, or {@code null} if {@code getCodeSize() == 0} or if the
* code is not ready.
* @return {@code null} if {@code getLinkedCodeSize() <= 0} otherwise the bytecode of the method
* whose length is guaranteed to be {@code > 0}
*/
byte[] getCode();

/**
* Returns the size of the bytecode of this method, if the method has code. This is equivalent
* to {@link #getCode()}. {@code length} if the method has code.
* Returns the size of the method's bytecode. If this method returns a value {@code > 0} then
* {@link #getCode()} will not return {@code null}.
*
* @return the size of the bytecode in bytes, or 0 if no bytecode is available
* @return 0 if the method has no bytecode, {@code -1} if the method does have bytecode but its
* {@linkplain #getDeclaringClass() declaring class} is not
* {@linkplain ResolvedJavaType#isLinked() linked} otherwise the size of the bytecode in
* bytes (guaranteed to be {@code > 0})
*/
int getCodeSize();

Expand Down Expand Up @@ -439,15 +441,11 @@ default <T extends Annotation> T[] getParameterAnnotations(Class<T> annotationCl
}

/**
* Checks whether the method has bytecodes associated with it. Note that even if this method
* returns {@code true}, {@link #getCode} can return {@code null} if
* {@linkplain #getDeclaringClass() declaring class} is not
* {@linkplain ResolvedJavaType#isLinked() linked}.
*
* @return {@code this.getCodeSize() != 0}
* @see #getCodeSize()
* @return {@code getCodeSize() > 0}
*/
default boolean hasBytecodes() {
return getCodeSize() != 0;
return getCodeSize() > 0;
}

/**
Expand Down
Expand Up @@ -339,13 +339,33 @@ default ResolvedJavaMethod resolveConcreteMethod(ResolvedJavaMethod method, Reso
*/
ResolvedJavaMethod[] getDeclaredConstructors();

/**
* Returns an array reflecting all the constructors declared by this type. This method is
* similar to {@link Class#getDeclaredConstructors()} in terms of returned constructors.
*
* @param forceLink if {@code true}, forces this type to be {@link #link linked}
*/
default ResolvedJavaMethod[] getDeclaredConstructors(boolean forceLink) {
throw new UnsupportedOperationException();
}

/**
* Returns an array reflecting all the methods declared by this type. This method is similar to
* {@link Class#getDeclaredMethods()} in terms of returned methods. Calling this method forces
* this type to be {@link #link linked}.
*/
ResolvedJavaMethod[] getDeclaredMethods();

/**
* Returns an array reflecting all the methods declared by this type. This method is similar to
* {@link Class#getDeclaredMethods()} in terms of returned methods.
*
* @param forceLink if {@code true}, forces this type to be {@link #link linked}
*/
default ResolvedJavaMethod[] getDeclaredMethods(boolean forceLink) {
throw new UnsupportedOperationException();
}

/**
* Returns the {@code <clinit>} method for this class if there is one.
*/
Expand Down
@@ -0,0 +1,145 @@
/*
* Copyright (c) 2022, 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 jdk.vm.ci.hotspot.test;

import static java.lang.reflect.Modifier.FINAL;
import static java.lang.reflect.Modifier.PRIVATE;
import static java.lang.reflect.Modifier.PROTECTED;
import static java.lang.reflect.Modifier.PUBLIC;
import static java.lang.reflect.Modifier.STATIC;
import static java.lang.reflect.Modifier.TRANSIENT;
import static java.lang.reflect.Modifier.VOLATILE;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import org.junit.Assert;
import org.junit.Test;

import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
import jdk.vm.ci.hotspot.HotSpotResolvedJavaField;
import jdk.vm.ci.hotspot.HotSpotVMConfigAccess;
import jdk.vm.ci.meta.JavaType;
import jdk.vm.ci.meta.MetaAccessProvider;
import jdk.vm.ci.meta.ResolvedJavaField;
import jdk.vm.ci.meta.ResolvedJavaType;
import jdk.vm.ci.runtime.JVMCI;

/**
* Tests {@link HotSpotResolvedJavaField} functionality.
*/
public class HotSpotResolvedJavaFieldTest {

private static final Class<?>[] classesWithInternalFields = {Class.class, ClassLoader.class};

private static final Method createFieldMethod;
private static final Field indexField;

static {
Method m = null;
Field f = null;
try {
Class<?> typeImpl = Class.forName("jdk.vm.ci.hotspot.HotSpotResolvedObjectTypeImpl");
m = typeImpl.getDeclaredMethod("createField", JavaType.class, long.class, int.class, int.class);
m.setAccessible(true);
Class<?> fieldImpl = Class.forName("jdk.vm.ci.hotspot.HotSpotResolvedJavaFieldImpl");
f = fieldImpl.getDeclaredField("index");
f.setAccessible(true);
} catch (Exception e) {
throw new AssertionError(e);
}

createFieldMethod = m;
indexField = f;
}

/**
* Same as {@code HotSpotModifiers.jvmFieldModifiers()} but works when using a JVMCI version
* prior to the introduction of that method.
*/
private int jvmFieldModifiers() {
HotSpotJVMCIRuntime runtime = runtime();
HotSpotVMConfigAccess access = new HotSpotVMConfigAccess(runtime.getConfigStore());
int accEnum = access.getConstant("JVM_ACC_ENUM", Integer.class, 0x4000);
int accSynthetic = access.getConstant("JVM_ACC_SYNTHETIC", Integer.class, 0x1000);
return PUBLIC | PRIVATE | PROTECTED | STATIC | FINAL | VOLATILE | TRANSIENT | accEnum | accSynthetic;
}

HotSpotJVMCIRuntime runtime() {
return (HotSpotJVMCIRuntime) JVMCI.getRuntime();
}

MetaAccessProvider getMetaAccess() {
return runtime().getHostJVMCIBackend().getMetaAccess();
}

/**
* Tests that {@link HotSpotResolvedJavaField#getModifiers()} only includes the modifiers
* returned by {@link Field#getModifiers()}. Namely, it must not include
* {@code HotSpotResolvedJavaField#FIELD_INTERNAL_FLAG}.
*/
@Test
public void testModifiersForInternal() {
for (Class<?> c : classesWithInternalFields) {
ResolvedJavaType type = getMetaAccess().lookupJavaType(c);
for (ResolvedJavaField field : type.getInstanceFields(false)) {
if (field.isInternal()) {
Assert.assertEquals(0, ~jvmFieldModifiers() & field.getModifiers());
}
}
}
}

/**
* Tests that {@code HotSpotResolvedObjectTypeImpl#createField(String, JavaType, long, int)}
* always returns an {@linkplain ResolvedJavaField#equals(Object) equivalent} object for an
* internal field.
*
* @throws InvocationTargetException
* @throws IllegalArgumentException
* @throws IllegalAccessException
*/
@Test
public void testEquivalenceForInternalFields() throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
for (Class<?> c : classesWithInternalFields) {
ResolvedJavaType type = getMetaAccess().lookupJavaType(c);
for (ResolvedJavaField field : type.getInstanceFields(false)) {
if (field.isInternal()) {
HotSpotResolvedJavaField expected = (HotSpotResolvedJavaField) field;
int index = indexField.getInt(expected);
ResolvedJavaField actual = (ResolvedJavaField) createFieldMethod.invoke(type, expected.getType(), expected.getOffset(), expected.getModifiers(), index);
Assert.assertEquals(expected, actual);
}
}
}
}

@Test
public void testIsInObject() {
for (Field f : String.class.getDeclaredFields()) {
HotSpotResolvedJavaField rf = (HotSpotResolvedJavaField) getMetaAccess().lookupJavaField(f);
Assert.assertEquals(rf.toString(), rf.isInObject(runtime().getHostJVMCIBackend().getConstantReflection().forString("a string")), !rf.isStatic());
}
}
}

1 comment on commit b464cc2

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

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

Please sign in to comment.