Skip to content

Commit 7df0c10

Browse files
author
Doug Simon
committedApr 22, 2021
8265480: add basic JVMCI support for JEP 309: Dynamic Class-File Constants
Reviewed-by: kvn, psandoz
1 parent 9499175 commit 7df0c10

File tree

10 files changed

+391
-31
lines changed

10 files changed

+391
-31
lines changed
 

‎src/hotspot/share/jvmci/jvmciCompilerToVM.cpp

+48-7
Original file line numberDiff line numberDiff line change
@@ -505,10 +505,11 @@ C2V_END
505505

506506
C2V_VMENTRY_0(jboolean, isCompilable,(JNIEnv* env, jobject, jobject jvmci_method))
507507
Method* method = JVMCIENV->asMethod(jvmci_method);
508-
ConstantPool* cp = method->constMethod()->constants();
509-
assert(cp != NULL, "npe");
510-
// don't inline method when constant pool contains a CONSTANT_Dynamic
511-
return !method->is_not_compilable(CompLevel_full_optimization) && !cp->has_dynamic_constant();
508+
// Skip redefined methods
509+
if (method->is_old()) {
510+
return false;
511+
}
512+
return !method->is_not_compilable(CompLevel_full_optimization);
512513
C2V_END
513514

514515
C2V_VMENTRY_0(jboolean, hasNeverInlineDirective,(JNIEnv* env, jobject, jobject jvmci_method))
@@ -624,8 +625,48 @@ C2V_VMENTRY_NULL(jobject, lookupClass, (JNIEnv* env, jobject, jclass mirror))
624625

625626
C2V_VMENTRY_NULL(jobject, resolvePossiblyCachedConstantInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index))
626627
constantPoolHandle cp(THREAD, JVMCIENV->asConstantPool(jvmci_constant_pool));
627-
oop result = cp->resolve_possibly_cached_constant_at(index, CHECK_NULL);
628-
return JVMCIENV->get_jobject(JVMCIENV->get_object_constant(result));
628+
oop obj = cp->resolve_possibly_cached_constant_at(index, CHECK_NULL);
629+
constantTag tag = cp->tag_at(index);
630+
if (tag.is_dynamic_constant() || tag.is_dynamic_constant_in_error()) {
631+
if (obj == Universe::the_null_sentinel()) {
632+
return JVMCIENV->get_jobject(JVMCIENV->get_JavaConstant_NULL_POINTER());
633+
}
634+
BasicType bt = Signature::basic_type(cp->uncached_signature_ref_at(index));
635+
if (!is_reference_type(bt)) {
636+
if (!is_java_primitive(bt)) {
637+
return JVMCIENV->get_jobject(JVMCIENV->get_JavaConstant_ILLEGAL());
638+
}
639+
640+
// Convert standard box (e.g. java.lang.Integer) to JVMCI box (e.g. jdk.vm.ci.meta.PrimitiveConstant)
641+
jvalue value;
642+
jlong raw_value;
643+
BasicType bt2 = java_lang_boxing_object::get_value(obj, &value);
644+
assert(bt2 == bt, "");
645+
switch (bt2) {
646+
case T_BOOLEAN: raw_value = value.z; break;
647+
case T_BYTE: raw_value = value.b; break;
648+
case T_SHORT: raw_value = value.s; break;
649+
case T_CHAR: raw_value = value.c; break;
650+
case T_INT: raw_value = value.i; break;
651+
case T_LONG: raw_value = value.j; break;
652+
case T_FLOAT: {
653+
JVMCIObject result = JVMCIENV->call_JavaConstant_forFloat(value.f, JVMCI_CHECK_NULL);
654+
return JVMCIENV->get_jobject(result);
655+
}
656+
case T_DOUBLE: {
657+
JVMCIObject result = JVMCIENV->call_JavaConstant_forDouble(value.d, JVMCI_CHECK_NULL);
658+
return JVMCIENV->get_jobject(result);
659+
}
660+
default: {
661+
return JVMCIENV->get_jobject(JVMCIENV->get_JavaConstant_ILLEGAL());
662+
}
663+
}
664+
665+
JVMCIObject result = JVMCIENV->call_PrimitiveConstant_forTypeChar(type2char(bt2), raw_value, JVMCI_CHECK_NULL);
666+
return JVMCIENV->get_jobject(result);
667+
}
668+
}
669+
return JVMCIENV->get_jobject(JVMCIENV->get_object_constant(obj));
629670
C2V_END
630671

631672
C2V_VMENTRY_0(jint, lookupNameAndTypeRefIndexInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index))
@@ -2700,7 +2741,7 @@ JNINativeMethod CompilerToVM::methods[] = {
27002741
{CC "lookupAppendixInPool", CC "(" HS_CONSTANT_POOL "I)" OBJECTCONSTANT, FN_PTR(lookupAppendixInPool)},
27012742
{CC "lookupMethodInPool", CC "(" HS_CONSTANT_POOL "IB)" HS_RESOLVED_METHOD, FN_PTR(lookupMethodInPool)},
27022743
{CC "constantPoolRemapInstructionOperandFromCache", CC "(" HS_CONSTANT_POOL "I)I", FN_PTR(constantPoolRemapInstructionOperandFromCache)},
2703-
{CC "resolvePossiblyCachedConstantInPool", CC "(" HS_CONSTANT_POOL "I)" OBJECTCONSTANT, FN_PTR(resolvePossiblyCachedConstantInPool)},
2744+
{CC "resolvePossiblyCachedConstantInPool", CC "(" HS_CONSTANT_POOL "I)" JAVACONSTANT, FN_PTR(resolvePossiblyCachedConstantInPool)},
27042745
{CC "resolveTypeInPool", CC "(" HS_CONSTANT_POOL "I)" HS_RESOLVED_KLASS, FN_PTR(resolveTypeInPool)},
27052746
{CC "resolveFieldInPool", CC "(" HS_CONSTANT_POOL "I" HS_RESOLVED_METHOD "B[I)" HS_RESOLVED_KLASS, FN_PTR(resolveFieldInPool)},
27062747
{CC "resolveInvokeDynamicInPool", CC "(" HS_CONSTANT_POOL "I)V", FN_PTR(resolveInvokeDynamicInPool)},

‎src/hotspot/share/jvmci/jvmciJavaClasses.hpp

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -245,6 +245,7 @@
245245
int_field(BytecodePosition, bci) \
246246
end_class \
247247
start_class(JavaConstant, jdk_vm_ci_meta_JavaConstant) \
248+
static_object_field(JavaConstant, ILLEGAL, "Ljdk/vm/ci/meta/PrimitiveConstant;") \
248249
static_object_field(JavaConstant, NULL_POINTER, "Ljdk/vm/ci/meta/JavaConstant;") \
249250
jvmci_method(CallStaticObjectMethod, GetStaticMethodID, call_static, JVMCIObject, JavaConstant, forFloat, forFloat_signature, (JVMCIObject kind, jlong value, JVMCI_TRAPS)) \
250251
jvmci_method(CallStaticObjectMethod, GetStaticMethodID, call_static, JVMCIObject, JavaConstant, forDouble, forDouble_signature, (JVMCIObject kind, jlong value, JVMCI_TRAPS)) \
@@ -286,7 +287,9 @@
286287
static_object_field(JavaKind, Char, "Ljdk/vm/ci/meta/JavaKind;") \
287288
static_object_field(JavaKind, Short, "Ljdk/vm/ci/meta/JavaKind;") \
288289
static_object_field(JavaKind, Int, "Ljdk/vm/ci/meta/JavaKind;") \
290+
static_object_field(JavaKind, Float, "Ljdk/vm/ci/meta/JavaKind;") \
289291
static_object_field(JavaKind, Long, "Ljdk/vm/ci/meta/JavaKind;") \
292+
static_object_field(JavaKind, Double, "Ljdk/vm/ci/meta/JavaKind;") \
290293
end_class \
291294
start_class(ValueKind, jdk_vm_ci_meta_ValueKind) \
292295
object_field(ValueKind, platformKind, "Ljdk/vm/ci/meta/PlatformKind;") \

‎src/hotspot/share/jvmci/vmStructs_jvmci.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,7 @@
430430
declare_constant(JVM_CONSTANT_MethodHandle) \
431431
declare_constant(JVM_CONSTANT_MethodType) \
432432
declare_constant(JVM_CONSTANT_InvokeDynamic) \
433+
declare_constant(JVM_CONSTANT_Dynamic) \
433434
declare_constant(JVM_CONSTANT_Module) \
434435
declare_constant(JVM_CONSTANT_Package) \
435436
declare_constant(JVM_CONSTANT_ExternalMax) \

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

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -215,11 +215,11 @@ public static CompilerToVM compilerToVM() {
215215
* constant pool cache first.
216216
*
217217
* The behavior of this method is undefined if {@code cpi} does not denote one of the following
218-
* entry types: {@code JVM_CONSTANT_String}, {@code JVM_CONSTANT_MethodHandle},
219-
* {@code JVM_CONSTANT_MethodHandleInError}, {@code JVM_CONSTANT_MethodType} and
220-
* {@code JVM_CONSTANT_MethodTypeInError}.
218+
* entry types: {@code JVM_CONSTANT_Dynamic}, {@code JVM_CONSTANT_String},
219+
* {@code JVM_CONSTANT_MethodHandle}, {@code JVM_CONSTANT_MethodHandleInError},
220+
* {@code JVM_CONSTANT_MethodType} and {@code JVM_CONSTANT_MethodTypeInError}.
221221
*/
222-
native HotSpotObjectConstantImpl resolvePossiblyCachedConstantInPool(HotSpotConstantPool constantPool, int cpi);
222+
native JavaConstant resolvePossiblyCachedConstantInPool(HotSpotConstantPool constantPool, int cpi);
223223

224224
/**
225225
* Gets the {@code JVM_CONSTANT_NameAndType} index from the entry at index {@code cpi} in

‎src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotConstantPool.java

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -140,6 +140,8 @@ static final class JvmConstants {
140140
final JvmConstant jvmMethodType = add(new JvmConstant(c.jvmConstantMethodType, "MethodType"));
141141
final JvmConstant jvmMethodTypeInError = add(new JvmConstant(c.jvmConstantMethodTypeInError, "MethodTypeInError"));
142142
final JvmConstant jvmInvokeDynamic = add(new JvmConstant(c.jvmConstantInvokeDynamic, "InvokeDynamic"));
143+
final JvmConstant jvmDynamic = add(new JvmConstant(c.jvmConstantDynamic, "Dynamic"));
144+
final JvmConstant jvmDynamicInError = add(new JvmConstant(c.jvmConstantDynamicInError, "DynamicInError"));
143145

144146
private JvmConstant add(JvmConstant constant) {
145147
table[indexOf(constant.tag)] = constant;
@@ -545,6 +547,8 @@ public Object lookupConstant(int cpi) {
545547
case "MethodHandleInError":
546548
case "MethodType":
547549
case "MethodTypeInError":
550+
case "Dynamic":
551+
case "DynamicInError":
548552
return compilerToVM().resolvePossiblyCachedConstantInPool(this, cpi);
549553
default:
550554
throw new JVMCIError("Unknown constant pool tag %s", tag);

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

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -255,6 +255,8 @@ long arrayPrototypeMarkWord() {
255255
final int jvmConstantMethodHandleInError = getConstant("JVM_CONSTANT_MethodHandleInError", Integer.class);
256256
final int jvmConstantMethodType = getConstant("JVM_CONSTANT_MethodType", Integer.class);
257257
final int jvmConstantMethodTypeInError = getConstant("JVM_CONSTANT_MethodTypeInError", Integer.class);
258+
final int jvmConstantDynamic = getConstant("JVM_CONSTANT_Dynamic", Integer.class);
259+
final int jvmConstantDynamicInError = getConstant("JVM_CONSTANT_DynamicInError", Integer.class);
258260
final int jvmConstantInvokeDynamic = getConstant("JVM_CONSTANT_InvokeDynamic", Integer.class);
259261

260262
final int jvmConstantExternalMax = getConstant("JVM_CONSTANT_ExternalMax", Integer.class);

‎src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaConstant.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2009, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -46,6 +46,7 @@ public interface JavaConstant extends Constant, JavaValue {
4646
PrimitiveConstant DOUBLE_1 = new PrimitiveConstant(JavaKind.Double, Double.doubleToRawLongBits(1.0D));
4747
PrimitiveConstant TRUE = new PrimitiveConstant(JavaKind.Boolean, 1L);
4848
PrimitiveConstant FALSE = new PrimitiveConstant(JavaKind.Boolean, 0L);
49+
PrimitiveConstant ILLEGAL = new PrimitiveConstant(JavaKind.Illegal, 0);
4950

5051
/**
5152
* Returns the Java kind of this constant.
@@ -329,7 +330,7 @@ static PrimitiveConstant forBoxedPrimitive(Object value) {
329330
}
330331

331332
static PrimitiveConstant forIllegal() {
332-
return new PrimitiveConstant(JavaKind.Illegal, 0);
333+
return JavaConstant.ILLEGAL;
333334
}
334335

335336
/**

‎src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaKind.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2009, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -473,7 +473,7 @@ public int getBitCount() {
473473
case Long:
474474
return 64;
475475
default:
476-
throw new IllegalArgumentException("illegal call to bits on " + this);
476+
throw new IllegalArgumentException("illegal call to getBitCount() on " + this);
477477
}
478478
}
479479
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,304 @@
1+
/*
2+
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
/*
25+
* @test
26+
* @requires vm.jvmci
27+
* @summary Test CONSTANT_Dynamic resolution by HotSpotConstantPool.
28+
* @modules java.base/jdk.internal.org.objectweb.asm
29+
* jdk.internal.vm.ci/jdk.vm.ci.hotspot:+open
30+
* jdk.internal.vm.ci/jdk.vm.ci.runtime
31+
* jdk.internal.vm.ci/jdk.vm.ci.meta
32+
* @run testng/othervm
33+
* -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI -XX:-UseJVMCICompiler
34+
* jdk.vm.ci.hotspot.test.TestDynamicConstant
35+
*/
36+
37+
package jdk.vm.ci.hotspot.test;
38+
39+
import java.io.File;
40+
import java.io.IOException;
41+
import java.lang.invoke.ConstantBootstraps;
42+
import java.lang.invoke.MethodHandles;
43+
import java.lang.reflect.Method;
44+
import java.nio.file.Files;
45+
import java.util.List;
46+
47+
import org.testng.Assert;
48+
import org.testng.annotations.Test;
49+
50+
import jdk.internal.org.objectweb.asm.ClassWriter;
51+
import jdk.internal.org.objectweb.asm.ConstantDynamic;
52+
import jdk.internal.org.objectweb.asm.Handle;
53+
import jdk.internal.org.objectweb.asm.MethodVisitor;
54+
import jdk.internal.org.objectweb.asm.Opcodes;
55+
import jdk.internal.org.objectweb.asm.Type;
56+
import jdk.vm.ci.hotspot.HotSpotObjectConstant;
57+
import jdk.vm.ci.meta.ConstantPool;
58+
import jdk.vm.ci.meta.MetaAccessProvider;
59+
import jdk.vm.ci.meta.PrimitiveConstant;
60+
import jdk.vm.ci.meta.ResolvedJavaMethod;
61+
import jdk.vm.ci.runtime.JVMCI;
62+
63+
/**
64+
* Tests support for Dynamic constants.
65+
*
66+
* @see "https://openjdk.java.net/jeps/309"
67+
* @see "https://bugs.openjdk.java.net/browse/JDK-8177279"
68+
*/
69+
public class TestDynamicConstant implements Opcodes {
70+
71+
private static final int PUBLIC_STATIC = ACC_PUBLIC | ACC_STATIC;
72+
73+
static final String testClassInternalName = Type.getInternalName(TestDynamicConstant.class);
74+
static final String constantBootstrapsClassInternalName = Type.getInternalName(ConstantBootstraps.class);
75+
76+
enum CondyType {
77+
/**
78+
* Condy whose bootstrap method is one of the {@code TestDynamicConstant.get<type>BSM()}
79+
* methods.
80+
*/
81+
CALL_DIRECT_BSM,
82+
83+
/**
84+
* Condy whose bootstrap method is {@link ConstantBootstraps#invoke} that invokes one of the
85+
* {@code TestDynamicConstant.get<type>()} methods.
86+
*/
87+
CALL_INDIRECT_BSM,
88+
89+
/**
90+
* Condy whose bootstrap method is {@link ConstantBootstraps#invoke} that invokes one of the
91+
* {@code TestDynamicConstant.get<type>(<type> p1, <type> p2)} methods with args that are
92+
* condys themselves.
93+
*/
94+
CALL_INDIRECT_WITH_ARGS_BSM
95+
}
96+
97+
/**
98+
* Generates a class with a static {@code run} method that returns a value loaded from
99+
* CONSTANT_Dynamic constant pool entry.
100+
*/
101+
static class TestGenerator {
102+
103+
/**
104+
* Type of value returned by the generated {@code run} method.
105+
*/
106+
final Type type;
107+
108+
/**
109+
* Type of condy used to produce the returned value.
110+
*/
111+
final CondyType condyType;
112+
113+
/**
114+
* Base name of the static {@code TestDynamicConstant.get<type>} method(s) invoked from
115+
* condys in the generated class.
116+
*/
117+
final String getter;
118+
119+
/**
120+
* Name of the generated class.
121+
*/
122+
final String className;
123+
124+
TestGenerator(Class<?> type, CondyType condyType) {
125+
String typeName = type.getSimpleName();
126+
this.type = Type.getType(type);
127+
this.condyType = condyType;
128+
this.getter = "get" + typeName.substring(0, 1).toUpperCase() + typeName.substring(1);
129+
this.className = TestDynamicConstant.class.getName() + "$" + typeName + '_' + condyType;
130+
}
131+
132+
Class<?> generateClass() throws ClassNotFoundException {
133+
TestCL cl = new TestCL(getClass().getClassLoader());
134+
return cl.findClass(className);
135+
}
136+
137+
byte[] generateClassfile() {
138+
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
139+
cw.visit(V16, ACC_SUPER | ACC_PUBLIC, className.replace('.', '/'), null, "java/lang/Object", null);
140+
141+
// @formatter:off
142+
// Object ConstantBootstraps.invoke(MethodHandles.Lookup lookup, String name, Class<?> type, MethodHandle handle, Object... args)
143+
// @formatter:on
144+
String invokeSig = "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;Ljava/lang/invoke/MethodHandle;[Ljava/lang/Object;)Ljava/lang/Object;";
145+
Handle invokeHandle = new Handle(H_INVOKESTATIC, constantBootstrapsClassInternalName, "invoke", invokeSig, false);
146+
147+
String desc = type.getDescriptor();
148+
if (condyType == CondyType.CALL_DIRECT_BSM) {
149+
// Example: int TestDynamicConstant.getIntBSM(MethodHandles.Lookup l, String name,
150+
// Class<?> type)
151+
String sig = "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;)" + desc;
152+
Handle handle = new Handle(H_INVOKESTATIC, testClassInternalName, getter + "BSM", sig, false);
153+
154+
ConstantDynamic condy = new ConstantDynamic("const", desc, handle);
155+
MethodVisitor run = cw.visitMethod(PUBLIC_STATIC, "run", "()" + desc, null, null);
156+
run.visitLdcInsn(condy);
157+
run.visitInsn(type.getOpcode(IRETURN));
158+
run.visitMaxs(0, 0);
159+
run.visitEnd();
160+
} else if (condyType == CondyType.CALL_INDIRECT_BSM) {
161+
// Example: int TestDynamicConstant.getInt()
162+
Handle handle = new Handle(H_INVOKESTATIC, testClassInternalName, getter, "()" + desc, false);
163+
164+
ConstantDynamic condy = new ConstantDynamic("const", desc, invokeHandle, handle);
165+
MethodVisitor run = cw.visitMethod(PUBLIC_STATIC, "run", "()" + desc, null, null);
166+
run.visitLdcInsn(condy);
167+
run.visitInsn(type.getOpcode(IRETURN));
168+
run.visitMaxs(0, 0);
169+
run.visitEnd();
170+
} else {
171+
assert condyType == CondyType.CALL_INDIRECT_WITH_ARGS_BSM;
172+
// Example: int TestDynamicConstant.getInt()
173+
Handle handle1 = new Handle(H_INVOKESTATIC, testClassInternalName, getter, "()" + desc, false);
174+
175+
// Example: int TestDynamicConstant.getInt(int v1, int v2)
176+
Handle handle2 = new Handle(H_INVOKESTATIC, testClassInternalName, getter, "(" + desc + desc + ")" + desc, false);
177+
178+
ConstantDynamic condy1 = new ConstantDynamic("const1", desc, invokeHandle, handle1);
179+
ConstantDynamic condy2 = new ConstantDynamic("const2", desc, invokeHandle, handle2, condy1, condy1);
180+
181+
MethodVisitor run = cw.visitMethod(PUBLIC_STATIC, "run", "()" + desc, null, null);
182+
run.visitLdcInsn(condy2);
183+
run.visitInsn(type.getOpcode(IRETURN));
184+
run.visitMaxs(0, 0);
185+
run.visitEnd();
186+
}
187+
cw.visitEnd();
188+
return cw.toByteArray();
189+
}
190+
191+
private final class TestCL extends ClassLoader {
192+
String saveClassfilesDir = System.getProperty("save.classfiles.dir");
193+
194+
private TestCL(ClassLoader parent) {
195+
super(parent);
196+
}
197+
198+
@Override
199+
protected Class<?> findClass(String name) throws ClassNotFoundException {
200+
if (name.equals(className)) {
201+
byte[] classfileBytes = generateClassfile();
202+
if (saveClassfilesDir != null) {
203+
try {
204+
File classfile = new File(saveClassfilesDir, name.replace('.', File.separatorChar) + ".class");
205+
File classfileDir = classfile.getParentFile();
206+
classfileDir.mkdirs();
207+
Files.write(classfile.toPath(), classfileBytes);
208+
System.out.println("Wrote: " + classfile.getAbsolutePath());
209+
} catch (IOException cause) {
210+
Assert.fail("Error saving class file for " + name, cause);
211+
}
212+
}
213+
return defineClass(name, classfileBytes, 0, classfileBytes.length);
214+
} else {
215+
return super.findClass(name);
216+
}
217+
}
218+
}
219+
}
220+
221+
@SuppressWarnings("try")
222+
@Test
223+
public void test() throws Throwable {
224+
MetaAccessProvider metaAccess = JVMCI.getRuntime().getHostJVMCIBackend().getMetaAccess();
225+
Class<?>[] types = {
226+
boolean.class,
227+
byte.class,
228+
short.class,
229+
char.class,
230+
int.class,
231+
float.class,
232+
long.class,
233+
double.class,
234+
String.class,
235+
List.class
236+
};
237+
for (Class<?> type : types) {
238+
for (CondyType condyType : CondyType.values()) {
239+
TestGenerator e = new TestGenerator(type, condyType);
240+
Class<?> testClass = e.generateClass();
241+
Method m = testClass.getDeclaredMethod("run");
242+
ResolvedJavaMethod run = metaAccess.lookupJavaMethod(m);
243+
ConstantPool cp = run.getConstantPool();
244+
Method getTagAt = cp.getClass().getDeclaredMethod("getTagAt", int.class);
245+
getTagAt.setAccessible(true);
246+
Object lastConstant = null;
247+
for (int cpi = 1; cpi < cp.length(); cpi++) {
248+
String tag = String.valueOf(getTagAt.invoke(cp, cpi));
249+
if (tag.equals("Dynamic")) {
250+
lastConstant = cp.lookupConstant(cpi);
251+
}
252+
}
253+
Assert.assertTrue(lastConstant != null, "No Dynamic entries in constant pool of " + testClass.getName());
254+
255+
// Execute code to resolve condy by execution and compare
256+
// with condy resolved via ConstantPool
257+
Object expect = m.invoke(null);
258+
Object actual;
259+
if (lastConstant instanceof PrimitiveConstant) {
260+
actual = ((PrimitiveConstant) lastConstant).asBoxedPrimitive();
261+
} else {
262+
actual = ((HotSpotObjectConstant) lastConstant).asObject(type);
263+
}
264+
Assert.assertEquals(actual, expect, m + ":");
265+
}
266+
}
267+
}
268+
269+
// @formatter:off
270+
@SuppressWarnings("unused") public static boolean getBooleanBSM(MethodHandles.Lookup l, String name, Class<?> type) { return true; }
271+
@SuppressWarnings("unused") public static char getCharBSM (MethodHandles.Lookup l, String name, Class<?> type) { return '*'; }
272+
@SuppressWarnings("unused") public static short getShortBSM (MethodHandles.Lookup l, String name, Class<?> type) { return Short.MAX_VALUE; }
273+
@SuppressWarnings("unused") public static byte getByteBSM (MethodHandles.Lookup l, String name, Class<?> type) { return Byte.MAX_VALUE; }
274+
@SuppressWarnings("unused") public static int getIntBSM (MethodHandles.Lookup l, String name, Class<?> type) { return Integer.MAX_VALUE; }
275+
@SuppressWarnings("unused") public static float getFloatBSM (MethodHandles.Lookup l, String name, Class<?> type) { return Float.MAX_VALUE; }
276+
@SuppressWarnings("unused") public static long getLongBSM (MethodHandles.Lookup l, String name, Class<?> type) { return Long.MAX_VALUE; }
277+
@SuppressWarnings("unused") public static double getDoubleBSM (MethodHandles.Lookup l, String name, Class<?> type) { return Double.MAX_VALUE; }
278+
@SuppressWarnings("unused") public static String getStringBSM (MethodHandles.Lookup l, String name, Class<?> type) { return "a string"; }
279+
@SuppressWarnings("unused") public static List<?> getListBSM (MethodHandles.Lookup l, String name, Class<?> type) { return List.of("element"); }
280+
281+
282+
public static boolean getBoolean() { return true; }
283+
public static char getChar () { return '*'; }
284+
public static short getShort () { return Short.MAX_VALUE; }
285+
public static byte getByte () { return Byte.MAX_VALUE; }
286+
public static int getInt () { return Integer.MAX_VALUE; }
287+
public static float getFloat () { return Float.MAX_VALUE; }
288+
public static long getLong () { return Long.MAX_VALUE; }
289+
public static double getDouble () { return Double.MAX_VALUE; }
290+
public static String getString () { return "a string"; }
291+
public static List<?> getList () { return List.of("element"); }
292+
293+
public static boolean getBoolean(boolean v1, boolean v2) { return v1 || v2; }
294+
public static char getChar (char v1, char v2) { return (char)(v1 ^ v2); }
295+
public static short getShort (short v1, short v2) { return (short)(v1 ^ v2); }
296+
public static byte getByte (byte v1, byte v2) { return (byte)(v1 ^ v2); }
297+
public static int getInt (int v1, int v2) { return v1 ^ v2; }
298+
public static float getFloat (float v1, float v2) { return v1 * v2; }
299+
public static long getLong (long v1, long v2) { return v1 ^ v2; }
300+
public static double getDouble (double v1, double v2) { return v1 * v2; }
301+
public static String getString (String v1, String v2) { return v1 + v2; }
302+
public static List<?> getList (List<?> v1, List<?> v2) { return List.of(v1, v2); }
303+
// @formatter:on
304+
}

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

+16-12
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -33,6 +33,17 @@
3333

3434
package jdk.vm.ci.runtime.test;
3535

36+
import static jdk.vm.ci.meta.MetaUtil.toInternalName;
37+
import static org.junit.Assert.assertEquals;
38+
import static org.junit.Assert.assertNotNull;
39+
import static org.junit.Assert.assertNull;
40+
import static org.junit.Assert.assertTrue;
41+
42+
import java.lang.reflect.Field;
43+
import java.lang.reflect.Method;
44+
45+
import org.junit.Test;
46+
3647
import jdk.vm.ci.meta.DeoptimizationAction;
3748
import jdk.vm.ci.meta.DeoptimizationReason;
3849
import jdk.vm.ci.meta.JavaConstant;
@@ -42,16 +53,6 @@
4253
import jdk.vm.ci.meta.ResolvedJavaMethod;
4354
import jdk.vm.ci.meta.ResolvedJavaType;
4455
import jdk.vm.ci.meta.Signature;
45-
import org.junit.Test;
46-
47-
import java.lang.reflect.Field;
48-
import java.lang.reflect.Method;
49-
50-
import static jdk.vm.ci.meta.MetaUtil.toInternalName;
51-
import static org.junit.Assert.assertEquals;
52-
import static org.junit.Assert.assertNotNull;
53-
import static org.junit.Assert.assertNull;
54-
import static org.junit.Assert.assertTrue;
5556

5657
/**
5758
* Tests for {@link MetaAccessProvider}.
@@ -117,7 +118,7 @@ public void lookupJavaTypesTest() {
117118
assertEquals("Unexpected javaType: " + result[counter] + " while expecting of class: " + aClass, result[counter].toClassName(), aClass.getName());
118119
}
119120
counter++;
120-
}
121+
}
121122
}
122123

123124
@Test(expected = NullPointerException.class)
@@ -187,6 +188,9 @@ public void lookupJavaTypeConstantNegativeTest() {
187188
public void getMemorySizeTest() {
188189
for (ConstantValue cv : constants()) {
189190
JavaConstant c = cv.value;
191+
if (c.getJavaKind() == JavaKind.Illegal) {
192+
continue;
193+
}
190194
long memSize = metaAccess.getMemorySize(c);
191195
if (c.isNull()) {
192196
assertEquals("Expected size = 0 for null", memSize, 0L);

0 commit comments

Comments
 (0)
Please sign in to comment.