Skip to content
This repository was archived by the owner on May 29, 2024. It is now read-only.

Commit e3462f1

Browse files
committed
[GR-24155] Add link, hasDefaultMethods and declaredDefaultMethods.
PullRequest: labsjdk-ce-11/92
2 parents ad22fea + d37006a commit e3462f1

File tree

8 files changed

+204
-2
lines changed

8 files changed

+204
-2
lines changed

src/hotspot/share/jvmci/jvmciCompilerToVM.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1768,6 +1768,18 @@ C2V_VMENTRY(void, ensureInitialized, (JNIEnv* env, jobject, jobject jvmci_type))
17681768
}
17691769
C2V_END
17701770

1771+
C2V_VMENTRY(void, ensureLinked, (JNIEnv* env, jobject, jobject jvmci_type))
1772+
if (jvmci_type == NULL) {
1773+
JVMCI_THROW(NullPointerException);
1774+
}
1775+
1776+
Klass* klass = JVMCIENV->asKlass(jvmci_type);
1777+
if (klass != NULL && klass->is_instance_klass()) {
1778+
InstanceKlass* k = InstanceKlass::cast(klass);
1779+
k->link_class(CHECK);
1780+
}
1781+
C2V_END
1782+
17711783
C2V_VMENTRY_0(jint, interpreterFrameSize, (JNIEnv* env, jobject, jobject bytecode_frame_handle))
17721784
if (bytecode_frame_handle == NULL) {
17731785
JVMCI_THROW_0(NullPointerException);
@@ -1901,6 +1913,8 @@ C2V_VMENTRY_NULL(jobjectArray, getDeclaredConstructors, (JNIEnv* env, jobject, j
19011913
}
19021914

19031915
InstanceKlass* iklass = InstanceKlass::cast(klass);
1916+
// Ensure class is linked
1917+
iklass->link_class(CHECK_NULL);
19041918

19051919
GrowableArray<Method*> constructors_array;
19061920
for (int i = 0; i < iklass->methods()->length(); i++) {
@@ -1928,6 +1942,8 @@ C2V_VMENTRY_NULL(jobjectArray, getDeclaredMethods, (JNIEnv* env, jobject, jobjec
19281942
}
19291943

19301944
InstanceKlass* iklass = InstanceKlass::cast(klass);
1945+
// Ensure class is linked
1946+
iklass->link_class(CHECK_NULL);
19311947

19321948
GrowableArray<Method*> methods_array;
19331949
for (int i = 0; i < iklass->methods()->length(); i++) {
@@ -2727,6 +2743,7 @@ JNINativeMethod CompilerToVM::methods[] = {
27272743
{CC "getInterfaces", CC "(" HS_RESOLVED_KLASS ")[" HS_RESOLVED_KLASS, FN_PTR(getInterfaces)},
27282744
{CC "getComponentType", CC "(" HS_RESOLVED_KLASS ")" HS_RESOLVED_TYPE, FN_PTR(getComponentType)},
27292745
{CC "ensureInitialized", CC "(" HS_RESOLVED_KLASS ")V", FN_PTR(ensureInitialized)},
2746+
{CC "ensureLinked", CC "(" HS_RESOLVED_KLASS ")V", FN_PTR(ensureLinked)},
27302747
{CC "getIdentityHashCode", CC "(" OBJECTCONSTANT ")I", FN_PTR(getIdentityHashCode)},
27312748
{CC "isInternedString", CC "(" OBJECTCONSTANT ")Z", FN_PTR(isInternedString)},
27322749
{CC "unboxPrimitive", CC "(" OBJECTCONSTANT ")" OBJECT, FN_PTR(unboxPrimitive)},

src/hotspot/share/jvmci/vmStructs_jvmci.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -542,7 +542,14 @@
542542
declare_constant(InstanceKlass::linked) \
543543
declare_constant(InstanceKlass::being_initialized) \
544544
declare_constant(InstanceKlass::fully_initialized) \
545+
\
546+
/*********************************/ \
547+
/* InstanceKlass _misc_flags */ \
548+
/*********************************/ \
549+
\
545550
declare_constant(InstanceKlass::_misc_is_anonymous) \
551+
declare_constant(InstanceKlass::_misc_has_nonstatic_concrete_methods) \
552+
declare_constant(InstanceKlass::_misc_declares_nonstatic_concrete_methods) \
546553
\
547554
declare_constant(JumpData::taken_off_set) \
548555
declare_constant(JumpData::displacement_off_set) \

src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -774,6 +774,11 @@ HotSpotResolvedObjectTypeImpl getResolvedJavaType(long displacement, boolean com
774774
*/
775775
native void ensureInitialized(HotSpotResolvedObjectTypeImpl type);
776776

777+
/**
778+
* Forces linking of {@code type}.
779+
*/
780+
native void ensureLinked(HotSpotResolvedObjectTypeImpl type);
781+
777782
/**
778783
* Checks if {@code object} is a String and is an interned string value.
779784
*/

src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,27 @@ public boolean isLinked() {
364364
return isArray() ? true : getInitState() >= config().instanceKlassStateLinked;
365365
}
366366

367+
@Override
368+
public void link() {
369+
if (!isLinked()) {
370+
runtime().compilerToVm.ensureLinked(this);
371+
}
372+
}
373+
374+
@Override
375+
public boolean hasDefaultMethods() {
376+
HotSpotVMConfig config = config();
377+
int miscFlags = UNSAFE.getChar(getMetaspaceKlass() + config.instanceKlassMiscFlagsOffset);
378+
return (miscFlags & config.jvmMiscFlagsHasDefaultMethods) != 0;
379+
}
380+
381+
@Override
382+
public boolean declaresDefaultMethods() {
383+
HotSpotVMConfig config = config();
384+
int miscFlags = UNSAFE.getChar(getMetaspaceKlass() + config.instanceKlassMiscFlagsOffset);
385+
return (miscFlags & config.jvmMiscFlagsDeclaresDefaultMethods) != 0;
386+
}
387+
367388
/**
368389
* Returns the value of the state field {@code InstanceKlass::_init_state} of the metaspace
369390
* klass.

src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,20 @@ public ResolvedJavaType resolve(ResolvedJavaType accessingClass) {
245245
public void initialize() {
246246
}
247247

248+
@Override
249+
public void link() {
250+
}
251+
252+
@Override
253+
public boolean hasDefaultMethods() {
254+
return false;
255+
}
256+
257+
@Override
258+
public boolean declaresDefaultMethods() {
259+
return false;
260+
}
261+
248262
@Override
249263
public ResolvedJavaField findInstanceFieldWithOffset(long offset, JavaKind expectedType) {
250264
return null;

src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,9 @@ String getHostArchitectureName() {
139139
final int jvmAccEnum = getConstant("JVM_ACC_ENUM", Integer.class);
140140
final int jvmAccInterface = getConstant("JVM_ACC_INTERFACE", Integer.class);
141141

142+
final int jvmMiscFlagsHasDefaultMethods = getConstant("InstanceKlass::_misc_has_nonstatic_concrete_methods", Integer.class);
143+
final int jvmMiscFlagsDeclaresDefaultMethods = getConstant("InstanceKlass::_misc_declares_nonstatic_concrete_methods", Integer.class);
144+
142145
// This is only valid on AMD64.
143146
final int runtimeCallStackSize = getConstant("frame::arg_reg_save_area_bytes", Integer.class, osArch.equals("amd64") ? null : 0);
144147

src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ResolvedJavaType.java

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,30 @@ default boolean isLeaf() {
105105
*/
106106
boolean isLinked();
107107

108+
/**
109+
* Links this type. If this method returns normally, then future calls of {@link #isLinked} will
110+
* return true and future calls of {@link #link} are no-ops. If the method throws an exception,
111+
* then future calls of {@link #isLinked} will return false and future calls of {@link #link}
112+
* will reattempt the linking step which might succeed or throw an exception.
113+
*/
114+
default void link() {
115+
throw new UnsupportedOperationException("link is unsupported");
116+
}
117+
118+
/**
119+
* Checks whether this type or any of its supertypes or superinterfaces has default methods.
120+
*/
121+
default boolean hasDefaultMethods() {
122+
throw new UnsupportedOperationException("hasDefaultMethods is unsupported");
123+
}
124+
125+
/**
126+
* Checks whether this type declares defaults methods.
127+
*/
128+
default boolean declaresDefaultMethods() {
129+
throw new UnsupportedOperationException("declaresDefaultMethods is unsupported");
130+
}
131+
108132
/**
109133
* Determines if this type is either the same as, or is a superclass or superinterface of, the
110134
* type represented by the specified parameter. This method is identical to
@@ -308,13 +332,15 @@ default ResolvedJavaMethod resolveConcreteMethod(ResolvedJavaMethod method, Reso
308332

309333
/**
310334
* Returns an array reflecting all the constructors declared by this type. This method is
311-
* similar to {@link Class#getDeclaredConstructors()} in terms of returned constructors.
335+
* similar to {@link Class#getDeclaredConstructors()} in terms of returned constructors. Calling
336+
* this method forces this type to be {@link #link linked}.
312337
*/
313338
ResolvedJavaMethod[] getDeclaredConstructors();
314339

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

test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@
4848
import static org.junit.Assert.assertNull;
4949
import static org.junit.Assert.assertTrue;
5050

51+
import java.io.DataInputStream;
52+
import java.io.IOException;
53+
import java.io.InputStream;
5154
import java.lang.annotation.Annotation;
5255
import java.lang.invoke.MethodHandles.Lookup;
5356
import java.lang.reflect.AccessibleObject;
@@ -63,6 +66,7 @@
6366
import java.util.Set;
6467
import java.util.function.Supplier;
6568

69+
import org.junit.Assert;
6670
import org.junit.Test;
6771

6872
import jdk.internal.reflect.ConstantPool;
@@ -323,6 +327,111 @@ public void findLeastCommonAncestorTest() {
323327
}
324328
}
325329

330+
@Test
331+
public void linkTest() {
332+
for (Class<?> c : classes) {
333+
ResolvedJavaType type = metaAccess.lookupJavaType(c);
334+
type.link();
335+
}
336+
}
337+
338+
private class HidingClassLoader extends ClassLoader {
339+
@Override
340+
protected Class<?> findClass(final String name) throws ClassNotFoundException {
341+
if (name.endsWith("MissingInterface")) {
342+
throw new ClassNotFoundException("missing");
343+
}
344+
byte[] classData = null;
345+
try {
346+
InputStream is = HidingClassLoader.class.getResourceAsStream("/" + name.replace('.', '/') + ".class");
347+
classData = new byte[is.available()];
348+
new DataInputStream(is).readFully(classData);
349+
} catch (IOException e) {
350+
Assert.fail("can't access class: " + name);
351+
}
352+
353+
return defineClass(null, classData, 0, classData.length);
354+
}
355+
356+
ResolvedJavaType lookupJavaType(String name) throws ClassNotFoundException {
357+
return metaAccess.lookupJavaType(loadClass(name));
358+
}
359+
360+
HidingClassLoader() {
361+
super(null);
362+
}
363+
364+
}
365+
366+
interface MissingInterface {
367+
}
368+
369+
static class MissingInterfaceImpl implements MissingInterface {
370+
}
371+
372+
interface SomeInterface {
373+
default MissingInterface someMethod() {
374+
return new MissingInterfaceImpl();
375+
}
376+
}
377+
378+
static class Wrapper implements SomeInterface {
379+
}
380+
381+
@Test
382+
public void linkExceptionTest() throws ClassNotFoundException {
383+
HidingClassLoader cl = new HidingClassLoader();
384+
ResolvedJavaType inner = cl.lookupJavaType(Wrapper.class.getName());
385+
assertTrue("expected default methods", inner.hasDefaultMethods());
386+
try {
387+
inner.link();
388+
assertFalse("link should throw an exception", true);
389+
} catch (NoClassDefFoundError e) {
390+
}
391+
}
392+
393+
@Test
394+
public void hasDefaultMethodsTest() {
395+
for (Class<?> c : classes) {
396+
ResolvedJavaType type = metaAccess.lookupJavaType(c);
397+
assertEquals(hasDefaultMethods(type), type.hasDefaultMethods());
398+
}
399+
}
400+
401+
@Test
402+
public void declaresDefaultMethodsTest() {
403+
for (Class<?> c : classes) {
404+
ResolvedJavaType type = metaAccess.lookupJavaType(c);
405+
assertEquals(declaresDefaultMethods(type), type.declaresDefaultMethods());
406+
}
407+
}
408+
409+
private static boolean hasDefaultMethods(ResolvedJavaType type) {
410+
if (!type.isInterface() && type.getSuperclass() != null && hasDefaultMethods(type.getSuperclass())) {
411+
return true;
412+
}
413+
for (ResolvedJavaType iface : type.getInterfaces()) {
414+
if (hasDefaultMethods(iface)) {
415+
return true;
416+
}
417+
}
418+
return declaresDefaultMethods(type);
419+
}
420+
421+
static boolean declaresDefaultMethods(ResolvedJavaType type) {
422+
if (!type.isInterface()) {
423+
/* Only interfaces can declare default methods. */
424+
return false;
425+
}
426+
for (ResolvedJavaMethod method : type.getDeclaredMethods()) {
427+
if (method.isDefault()) {
428+
assert !Modifier.isStatic(method.getModifiers()) : "Default method that is static?";
429+
return true;
430+
}
431+
}
432+
return false;
433+
}
434+
326435
private static class Base {
327436
}
328437

0 commit comments

Comments
 (0)