8265480: add basic JVMCI support for JEP 309: Dynamic Class-File Constants
Reviewed-by: kvn, psandoz
This commit is contained in:
parent
9499175064
commit
7df0c10a4d
@ -505,10 +505,11 @@ C2V_END
|
||||
|
||||
C2V_VMENTRY_0(jboolean, isCompilable,(JNIEnv* env, jobject, jobject jvmci_method))
|
||||
Method* method = JVMCIENV->asMethod(jvmci_method);
|
||||
ConstantPool* cp = method->constMethod()->constants();
|
||||
assert(cp != NULL, "npe");
|
||||
// don't inline method when constant pool contains a CONSTANT_Dynamic
|
||||
return !method->is_not_compilable(CompLevel_full_optimization) && !cp->has_dynamic_constant();
|
||||
// Skip redefined methods
|
||||
if (method->is_old()) {
|
||||
return false;
|
||||
}
|
||||
return !method->is_not_compilable(CompLevel_full_optimization);
|
||||
C2V_END
|
||||
|
||||
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))
|
||||
|
||||
C2V_VMENTRY_NULL(jobject, resolvePossiblyCachedConstantInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index))
|
||||
constantPoolHandle cp(THREAD, JVMCIENV->asConstantPool(jvmci_constant_pool));
|
||||
oop result = cp->resolve_possibly_cached_constant_at(index, CHECK_NULL);
|
||||
return JVMCIENV->get_jobject(JVMCIENV->get_object_constant(result));
|
||||
oop obj = cp->resolve_possibly_cached_constant_at(index, CHECK_NULL);
|
||||
constantTag tag = cp->tag_at(index);
|
||||
if (tag.is_dynamic_constant() || tag.is_dynamic_constant_in_error()) {
|
||||
if (obj == Universe::the_null_sentinel()) {
|
||||
return JVMCIENV->get_jobject(JVMCIENV->get_JavaConstant_NULL_POINTER());
|
||||
}
|
||||
BasicType bt = Signature::basic_type(cp->uncached_signature_ref_at(index));
|
||||
if (!is_reference_type(bt)) {
|
||||
if (!is_java_primitive(bt)) {
|
||||
return JVMCIENV->get_jobject(JVMCIENV->get_JavaConstant_ILLEGAL());
|
||||
}
|
||||
|
||||
// Convert standard box (e.g. java.lang.Integer) to JVMCI box (e.g. jdk.vm.ci.meta.PrimitiveConstant)
|
||||
jvalue value;
|
||||
jlong raw_value;
|
||||
BasicType bt2 = java_lang_boxing_object::get_value(obj, &value);
|
||||
assert(bt2 == bt, "");
|
||||
switch (bt2) {
|
||||
case T_BOOLEAN: raw_value = value.z; break;
|
||||
case T_BYTE: raw_value = value.b; break;
|
||||
case T_SHORT: raw_value = value.s; break;
|
||||
case T_CHAR: raw_value = value.c; break;
|
||||
case T_INT: raw_value = value.i; break;
|
||||
case T_LONG: raw_value = value.j; break;
|
||||
case T_FLOAT: {
|
||||
JVMCIObject result = JVMCIENV->call_JavaConstant_forFloat(value.f, JVMCI_CHECK_NULL);
|
||||
return JVMCIENV->get_jobject(result);
|
||||
}
|
||||
case T_DOUBLE: {
|
||||
JVMCIObject result = JVMCIENV->call_JavaConstant_forDouble(value.d, JVMCI_CHECK_NULL);
|
||||
return JVMCIENV->get_jobject(result);
|
||||
}
|
||||
default: {
|
||||
return JVMCIENV->get_jobject(JVMCIENV->get_JavaConstant_ILLEGAL());
|
||||
}
|
||||
}
|
||||
|
||||
JVMCIObject result = JVMCIENV->call_PrimitiveConstant_forTypeChar(type2char(bt2), raw_value, JVMCI_CHECK_NULL);
|
||||
return JVMCIENV->get_jobject(result);
|
||||
}
|
||||
}
|
||||
return JVMCIENV->get_jobject(JVMCIENV->get_object_constant(obj));
|
||||
C2V_END
|
||||
|
||||
C2V_VMENTRY_0(jint, lookupNameAndTypeRefIndexInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index))
|
||||
@ -2700,7 +2741,7 @@ JNINativeMethod CompilerToVM::methods[] = {
|
||||
{CC "lookupAppendixInPool", CC "(" HS_CONSTANT_POOL "I)" OBJECTCONSTANT, FN_PTR(lookupAppendixInPool)},
|
||||
{CC "lookupMethodInPool", CC "(" HS_CONSTANT_POOL "IB)" HS_RESOLVED_METHOD, FN_PTR(lookupMethodInPool)},
|
||||
{CC "constantPoolRemapInstructionOperandFromCache", CC "(" HS_CONSTANT_POOL "I)I", FN_PTR(constantPoolRemapInstructionOperandFromCache)},
|
||||
{CC "resolvePossiblyCachedConstantInPool", CC "(" HS_CONSTANT_POOL "I)" OBJECTCONSTANT, FN_PTR(resolvePossiblyCachedConstantInPool)},
|
||||
{CC "resolvePossiblyCachedConstantInPool", CC "(" HS_CONSTANT_POOL "I)" JAVACONSTANT, FN_PTR(resolvePossiblyCachedConstantInPool)},
|
||||
{CC "resolveTypeInPool", CC "(" HS_CONSTANT_POOL "I)" HS_RESOLVED_KLASS, FN_PTR(resolveTypeInPool)},
|
||||
{CC "resolveFieldInPool", CC "(" HS_CONSTANT_POOL "I" HS_RESOLVED_METHOD "B[I)" HS_RESOLVED_KLASS, FN_PTR(resolveFieldInPool)},
|
||||
{CC "resolveInvokeDynamicInPool", CC "(" HS_CONSTANT_POOL "I)V", FN_PTR(resolveInvokeDynamicInPool)},
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2021, 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
|
||||
@ -245,6 +245,7 @@
|
||||
int_field(BytecodePosition, bci) \
|
||||
end_class \
|
||||
start_class(JavaConstant, jdk_vm_ci_meta_JavaConstant) \
|
||||
static_object_field(JavaConstant, ILLEGAL, "Ljdk/vm/ci/meta/PrimitiveConstant;") \
|
||||
static_object_field(JavaConstant, NULL_POINTER, "Ljdk/vm/ci/meta/JavaConstant;") \
|
||||
jvmci_method(CallStaticObjectMethod, GetStaticMethodID, call_static, JVMCIObject, JavaConstant, forFloat, forFloat_signature, (JVMCIObject kind, jlong value, JVMCI_TRAPS)) \
|
||||
jvmci_method(CallStaticObjectMethod, GetStaticMethodID, call_static, JVMCIObject, JavaConstant, forDouble, forDouble_signature, (JVMCIObject kind, jlong value, JVMCI_TRAPS)) \
|
||||
@ -286,7 +287,9 @@
|
||||
static_object_field(JavaKind, Char, "Ljdk/vm/ci/meta/JavaKind;") \
|
||||
static_object_field(JavaKind, Short, "Ljdk/vm/ci/meta/JavaKind;") \
|
||||
static_object_field(JavaKind, Int, "Ljdk/vm/ci/meta/JavaKind;") \
|
||||
static_object_field(JavaKind, Float, "Ljdk/vm/ci/meta/JavaKind;") \
|
||||
static_object_field(JavaKind, Long, "Ljdk/vm/ci/meta/JavaKind;") \
|
||||
static_object_field(JavaKind, Double, "Ljdk/vm/ci/meta/JavaKind;") \
|
||||
end_class \
|
||||
start_class(ValueKind, jdk_vm_ci_meta_ValueKind) \
|
||||
object_field(ValueKind, platformKind, "Ljdk/vm/ci/meta/PlatformKind;") \
|
||||
|
@ -430,6 +430,7 @@
|
||||
declare_constant(JVM_CONSTANT_MethodHandle) \
|
||||
declare_constant(JVM_CONSTANT_MethodType) \
|
||||
declare_constant(JVM_CONSTANT_InvokeDynamic) \
|
||||
declare_constant(JVM_CONSTANT_Dynamic) \
|
||||
declare_constant(JVM_CONSTANT_Module) \
|
||||
declare_constant(JVM_CONSTANT_Package) \
|
||||
declare_constant(JVM_CONSTANT_ExternalMax) \
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2021, 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
|
||||
@ -215,11 +215,11 @@ final class CompilerToVM {
|
||||
* constant pool cache first.
|
||||
*
|
||||
* The behavior of this method is undefined if {@code cpi} does not denote one of the following
|
||||
* entry types: {@code JVM_CONSTANT_String}, {@code JVM_CONSTANT_MethodHandle},
|
||||
* {@code JVM_CONSTANT_MethodHandleInError}, {@code JVM_CONSTANT_MethodType} and
|
||||
* {@code JVM_CONSTANT_MethodTypeInError}.
|
||||
* entry types: {@code JVM_CONSTANT_Dynamic}, {@code JVM_CONSTANT_String},
|
||||
* {@code JVM_CONSTANT_MethodHandle}, {@code JVM_CONSTANT_MethodHandleInError},
|
||||
* {@code JVM_CONSTANT_MethodType} and {@code JVM_CONSTANT_MethodTypeInError}.
|
||||
*/
|
||||
native HotSpotObjectConstantImpl resolvePossiblyCachedConstantInPool(HotSpotConstantPool constantPool, int cpi);
|
||||
native JavaConstant resolvePossiblyCachedConstantInPool(HotSpotConstantPool constantPool, int cpi);
|
||||
|
||||
/**
|
||||
* Gets the {@code JVM_CONSTANT_NameAndType} index from the entry at index {@code cpi} in
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2021, 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
|
||||
@ -140,6 +140,8 @@ public final class HotSpotConstantPool implements ConstantPool, MetaspaceHandleO
|
||||
final JvmConstant jvmMethodType = add(new JvmConstant(c.jvmConstantMethodType, "MethodType"));
|
||||
final JvmConstant jvmMethodTypeInError = add(new JvmConstant(c.jvmConstantMethodTypeInError, "MethodTypeInError"));
|
||||
final JvmConstant jvmInvokeDynamic = add(new JvmConstant(c.jvmConstantInvokeDynamic, "InvokeDynamic"));
|
||||
final JvmConstant jvmDynamic = add(new JvmConstant(c.jvmConstantDynamic, "Dynamic"));
|
||||
final JvmConstant jvmDynamicInError = add(new JvmConstant(c.jvmConstantDynamicInError, "DynamicInError"));
|
||||
|
||||
private JvmConstant add(JvmConstant constant) {
|
||||
table[indexOf(constant.tag)] = constant;
|
||||
@ -545,6 +547,8 @@ public final class HotSpotConstantPool implements ConstantPool, MetaspaceHandleO
|
||||
case "MethodHandleInError":
|
||||
case "MethodType":
|
||||
case "MethodTypeInError":
|
||||
case "Dynamic":
|
||||
case "DynamicInError":
|
||||
return compilerToVM().resolvePossiblyCachedConstantInPool(this, cpi);
|
||||
default:
|
||||
throw new JVMCIError("Unknown constant pool tag %s", tag);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2021, 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
|
||||
@ -255,6 +255,8 @@ class HotSpotVMConfig extends HotSpotVMConfigAccess {
|
||||
final int jvmConstantMethodHandleInError = getConstant("JVM_CONSTANT_MethodHandleInError", Integer.class);
|
||||
final int jvmConstantMethodType = getConstant("JVM_CONSTANT_MethodType", Integer.class);
|
||||
final int jvmConstantMethodTypeInError = getConstant("JVM_CONSTANT_MethodTypeInError", Integer.class);
|
||||
final int jvmConstantDynamic = getConstant("JVM_CONSTANT_Dynamic", Integer.class);
|
||||
final int jvmConstantDynamicInError = getConstant("JVM_CONSTANT_DynamicInError", Integer.class);
|
||||
final int jvmConstantInvokeDynamic = getConstant("JVM_CONSTANT_InvokeDynamic", Integer.class);
|
||||
|
||||
final int jvmConstantExternalMax = getConstant("JVM_CONSTANT_ExternalMax", Integer.class);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2009, 2021, 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
|
||||
@ -46,6 +46,7 @@ public interface JavaConstant extends Constant, JavaValue {
|
||||
PrimitiveConstant DOUBLE_1 = new PrimitiveConstant(JavaKind.Double, Double.doubleToRawLongBits(1.0D));
|
||||
PrimitiveConstant TRUE = new PrimitiveConstant(JavaKind.Boolean, 1L);
|
||||
PrimitiveConstant FALSE = new PrimitiveConstant(JavaKind.Boolean, 0L);
|
||||
PrimitiveConstant ILLEGAL = new PrimitiveConstant(JavaKind.Illegal, 0);
|
||||
|
||||
/**
|
||||
* Returns the Java kind of this constant.
|
||||
@ -329,7 +330,7 @@ public interface JavaConstant extends Constant, JavaValue {
|
||||
}
|
||||
|
||||
static PrimitiveConstant forIllegal() {
|
||||
return new PrimitiveConstant(JavaKind.Illegal, 0);
|
||||
return JavaConstant.ILLEGAL;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2009, 2021, 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
|
||||
@ -473,7 +473,7 @@ public enum JavaKind {
|
||||
case Long:
|
||||
return 64;
|
||||
default:
|
||||
throw new IllegalArgumentException("illegal call to bits on " + this);
|
||||
throw new IllegalArgumentException("illegal call to getBitCount() on " + this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,304 @@
|
||||
/*
|
||||
* Copyright (c) 2021, 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @requires vm.jvmci
|
||||
* @summary Test CONSTANT_Dynamic resolution by HotSpotConstantPool.
|
||||
* @modules java.base/jdk.internal.org.objectweb.asm
|
||||
* jdk.internal.vm.ci/jdk.vm.ci.hotspot:+open
|
||||
* jdk.internal.vm.ci/jdk.vm.ci.runtime
|
||||
* jdk.internal.vm.ci/jdk.vm.ci.meta
|
||||
* @run testng/othervm
|
||||
* -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI -XX:-UseJVMCICompiler
|
||||
* jdk.vm.ci.hotspot.test.TestDynamicConstant
|
||||
*/
|
||||
|
||||
package jdk.vm.ci.hotspot.test;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.invoke.ConstantBootstraps;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.file.Files;
|
||||
import java.util.List;
|
||||
|
||||
import org.testng.Assert;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import jdk.internal.org.objectweb.asm.ClassWriter;
|
||||
import jdk.internal.org.objectweb.asm.ConstantDynamic;
|
||||
import jdk.internal.org.objectweb.asm.Handle;
|
||||
import jdk.internal.org.objectweb.asm.MethodVisitor;
|
||||
import jdk.internal.org.objectweb.asm.Opcodes;
|
||||
import jdk.internal.org.objectweb.asm.Type;
|
||||
import jdk.vm.ci.hotspot.HotSpotObjectConstant;
|
||||
import jdk.vm.ci.meta.ConstantPool;
|
||||
import jdk.vm.ci.meta.MetaAccessProvider;
|
||||
import jdk.vm.ci.meta.PrimitiveConstant;
|
||||
import jdk.vm.ci.meta.ResolvedJavaMethod;
|
||||
import jdk.vm.ci.runtime.JVMCI;
|
||||
|
||||
/**
|
||||
* Tests support for Dynamic constants.
|
||||
*
|
||||
* @see "https://openjdk.java.net/jeps/309"
|
||||
* @see "https://bugs.openjdk.java.net/browse/JDK-8177279"
|
||||
*/
|
||||
public class TestDynamicConstant implements Opcodes {
|
||||
|
||||
private static final int PUBLIC_STATIC = ACC_PUBLIC | ACC_STATIC;
|
||||
|
||||
static final String testClassInternalName = Type.getInternalName(TestDynamicConstant.class);
|
||||
static final String constantBootstrapsClassInternalName = Type.getInternalName(ConstantBootstraps.class);
|
||||
|
||||
enum CondyType {
|
||||
/**
|
||||
* Condy whose bootstrap method is one of the {@code TestDynamicConstant.get<type>BSM()}
|
||||
* methods.
|
||||
*/
|
||||
CALL_DIRECT_BSM,
|
||||
|
||||
/**
|
||||
* Condy whose bootstrap method is {@link ConstantBootstraps#invoke} that invokes one of the
|
||||
* {@code TestDynamicConstant.get<type>()} methods.
|
||||
*/
|
||||
CALL_INDIRECT_BSM,
|
||||
|
||||
/**
|
||||
* Condy whose bootstrap method is {@link ConstantBootstraps#invoke} that invokes one of the
|
||||
* {@code TestDynamicConstant.get<type>(<type> p1, <type> p2)} methods with args that are
|
||||
* condys themselves.
|
||||
*/
|
||||
CALL_INDIRECT_WITH_ARGS_BSM
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a class with a static {@code run} method that returns a value loaded from
|
||||
* CONSTANT_Dynamic constant pool entry.
|
||||
*/
|
||||
static class TestGenerator {
|
||||
|
||||
/**
|
||||
* Type of value returned by the generated {@code run} method.
|
||||
*/
|
||||
final Type type;
|
||||
|
||||
/**
|
||||
* Type of condy used to produce the returned value.
|
||||
*/
|
||||
final CondyType condyType;
|
||||
|
||||
/**
|
||||
* Base name of the static {@code TestDynamicConstant.get<type>} method(s) invoked from
|
||||
* condys in the generated class.
|
||||
*/
|
||||
final String getter;
|
||||
|
||||
/**
|
||||
* Name of the generated class.
|
||||
*/
|
||||
final String className;
|
||||
|
||||
TestGenerator(Class<?> type, CondyType condyType) {
|
||||
String typeName = type.getSimpleName();
|
||||
this.type = Type.getType(type);
|
||||
this.condyType = condyType;
|
||||
this.getter = "get" + typeName.substring(0, 1).toUpperCase() + typeName.substring(1);
|
||||
this.className = TestDynamicConstant.class.getName() + "$" + typeName + '_' + condyType;
|
||||
}
|
||||
|
||||
Class<?> generateClass() throws ClassNotFoundException {
|
||||
TestCL cl = new TestCL(getClass().getClassLoader());
|
||||
return cl.findClass(className);
|
||||
}
|
||||
|
||||
byte[] generateClassfile() {
|
||||
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
|
||||
cw.visit(V16, ACC_SUPER | ACC_PUBLIC, className.replace('.', '/'), null, "java/lang/Object", null);
|
||||
|
||||
// @formatter:off
|
||||
// Object ConstantBootstraps.invoke(MethodHandles.Lookup lookup, String name, Class<?> type, MethodHandle handle, Object... args)
|
||||
// @formatter:on
|
||||
String invokeSig = "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;Ljava/lang/invoke/MethodHandle;[Ljava/lang/Object;)Ljava/lang/Object;";
|
||||
Handle invokeHandle = new Handle(H_INVOKESTATIC, constantBootstrapsClassInternalName, "invoke", invokeSig, false);
|
||||
|
||||
String desc = type.getDescriptor();
|
||||
if (condyType == CondyType.CALL_DIRECT_BSM) {
|
||||
// Example: int TestDynamicConstant.getIntBSM(MethodHandles.Lookup l, String name,
|
||||
// Class<?> type)
|
||||
String sig = "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;)" + desc;
|
||||
Handle handle = new Handle(H_INVOKESTATIC, testClassInternalName, getter + "BSM", sig, false);
|
||||
|
||||
ConstantDynamic condy = new ConstantDynamic("const", desc, handle);
|
||||
MethodVisitor run = cw.visitMethod(PUBLIC_STATIC, "run", "()" + desc, null, null);
|
||||
run.visitLdcInsn(condy);
|
||||
run.visitInsn(type.getOpcode(IRETURN));
|
||||
run.visitMaxs(0, 0);
|
||||
run.visitEnd();
|
||||
} else if (condyType == CondyType.CALL_INDIRECT_BSM) {
|
||||
// Example: int TestDynamicConstant.getInt()
|
||||
Handle handle = new Handle(H_INVOKESTATIC, testClassInternalName, getter, "()" + desc, false);
|
||||
|
||||
ConstantDynamic condy = new ConstantDynamic("const", desc, invokeHandle, handle);
|
||||
MethodVisitor run = cw.visitMethod(PUBLIC_STATIC, "run", "()" + desc, null, null);
|
||||
run.visitLdcInsn(condy);
|
||||
run.visitInsn(type.getOpcode(IRETURN));
|
||||
run.visitMaxs(0, 0);
|
||||
run.visitEnd();
|
||||
} else {
|
||||
assert condyType == CondyType.CALL_INDIRECT_WITH_ARGS_BSM;
|
||||
// Example: int TestDynamicConstant.getInt()
|
||||
Handle handle1 = new Handle(H_INVOKESTATIC, testClassInternalName, getter, "()" + desc, false);
|
||||
|
||||
// Example: int TestDynamicConstant.getInt(int v1, int v2)
|
||||
Handle handle2 = new Handle(H_INVOKESTATIC, testClassInternalName, getter, "(" + desc + desc + ")" + desc, false);
|
||||
|
||||
ConstantDynamic condy1 = new ConstantDynamic("const1", desc, invokeHandle, handle1);
|
||||
ConstantDynamic condy2 = new ConstantDynamic("const2", desc, invokeHandle, handle2, condy1, condy1);
|
||||
|
||||
MethodVisitor run = cw.visitMethod(PUBLIC_STATIC, "run", "()" + desc, null, null);
|
||||
run.visitLdcInsn(condy2);
|
||||
run.visitInsn(type.getOpcode(IRETURN));
|
||||
run.visitMaxs(0, 0);
|
||||
run.visitEnd();
|
||||
}
|
||||
cw.visitEnd();
|
||||
return cw.toByteArray();
|
||||
}
|
||||
|
||||
private final class TestCL extends ClassLoader {
|
||||
String saveClassfilesDir = System.getProperty("save.classfiles.dir");
|
||||
|
||||
private TestCL(ClassLoader parent) {
|
||||
super(parent);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> findClass(String name) throws ClassNotFoundException {
|
||||
if (name.equals(className)) {
|
||||
byte[] classfileBytes = generateClassfile();
|
||||
if (saveClassfilesDir != null) {
|
||||
try {
|
||||
File classfile = new File(saveClassfilesDir, name.replace('.', File.separatorChar) + ".class");
|
||||
File classfileDir = classfile.getParentFile();
|
||||
classfileDir.mkdirs();
|
||||
Files.write(classfile.toPath(), classfileBytes);
|
||||
System.out.println("Wrote: " + classfile.getAbsolutePath());
|
||||
} catch (IOException cause) {
|
||||
Assert.fail("Error saving class file for " + name, cause);
|
||||
}
|
||||
}
|
||||
return defineClass(name, classfileBytes, 0, classfileBytes.length);
|
||||
} else {
|
||||
return super.findClass(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("try")
|
||||
@Test
|
||||
public void test() throws Throwable {
|
||||
MetaAccessProvider metaAccess = JVMCI.getRuntime().getHostJVMCIBackend().getMetaAccess();
|
||||
Class<?>[] types = {
|
||||
boolean.class,
|
||||
byte.class,
|
||||
short.class,
|
||||
char.class,
|
||||
int.class,
|
||||
float.class,
|
||||
long.class,
|
||||
double.class,
|
||||
String.class,
|
||||
List.class
|
||||
};
|
||||
for (Class<?> type : types) {
|
||||
for (CondyType condyType : CondyType.values()) {
|
||||
TestGenerator e = new TestGenerator(type, condyType);
|
||||
Class<?> testClass = e.generateClass();
|
||||
Method m = testClass.getDeclaredMethod("run");
|
||||
ResolvedJavaMethod run = metaAccess.lookupJavaMethod(m);
|
||||
ConstantPool cp = run.getConstantPool();
|
||||
Method getTagAt = cp.getClass().getDeclaredMethod("getTagAt", int.class);
|
||||
getTagAt.setAccessible(true);
|
||||
Object lastConstant = null;
|
||||
for (int cpi = 1; cpi < cp.length(); cpi++) {
|
||||
String tag = String.valueOf(getTagAt.invoke(cp, cpi));
|
||||
if (tag.equals("Dynamic")) {
|
||||
lastConstant = cp.lookupConstant(cpi);
|
||||
}
|
||||
}
|
||||
Assert.assertTrue(lastConstant != null, "No Dynamic entries in constant pool of " + testClass.getName());
|
||||
|
||||
// Execute code to resolve condy by execution and compare
|
||||
// with condy resolved via ConstantPool
|
||||
Object expect = m.invoke(null);
|
||||
Object actual;
|
||||
if (lastConstant instanceof PrimitiveConstant) {
|
||||
actual = ((PrimitiveConstant) lastConstant).asBoxedPrimitive();
|
||||
} else {
|
||||
actual = ((HotSpotObjectConstant) lastConstant).asObject(type);
|
||||
}
|
||||
Assert.assertEquals(actual, expect, m + ":");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// @formatter:off
|
||||
@SuppressWarnings("unused") public static boolean getBooleanBSM(MethodHandles.Lookup l, String name, Class<?> type) { return true; }
|
||||
@SuppressWarnings("unused") public static char getCharBSM (MethodHandles.Lookup l, String name, Class<?> type) { return '*'; }
|
||||
@SuppressWarnings("unused") public static short getShortBSM (MethodHandles.Lookup l, String name, Class<?> type) { return Short.MAX_VALUE; }
|
||||
@SuppressWarnings("unused") public static byte getByteBSM (MethodHandles.Lookup l, String name, Class<?> type) { return Byte.MAX_VALUE; }
|
||||
@SuppressWarnings("unused") public static int getIntBSM (MethodHandles.Lookup l, String name, Class<?> type) { return Integer.MAX_VALUE; }
|
||||
@SuppressWarnings("unused") public static float getFloatBSM (MethodHandles.Lookup l, String name, Class<?> type) { return Float.MAX_VALUE; }
|
||||
@SuppressWarnings("unused") public static long getLongBSM (MethodHandles.Lookup l, String name, Class<?> type) { return Long.MAX_VALUE; }
|
||||
@SuppressWarnings("unused") public static double getDoubleBSM (MethodHandles.Lookup l, String name, Class<?> type) { return Double.MAX_VALUE; }
|
||||
@SuppressWarnings("unused") public static String getStringBSM (MethodHandles.Lookup l, String name, Class<?> type) { return "a string"; }
|
||||
@SuppressWarnings("unused") public static List<?> getListBSM (MethodHandles.Lookup l, String name, Class<?> type) { return List.of("element"); }
|
||||
|
||||
|
||||
public static boolean getBoolean() { return true; }
|
||||
public static char getChar () { return '*'; }
|
||||
public static short getShort () { return Short.MAX_VALUE; }
|
||||
public static byte getByte () { return Byte.MAX_VALUE; }
|
||||
public static int getInt () { return Integer.MAX_VALUE; }
|
||||
public static float getFloat () { return Float.MAX_VALUE; }
|
||||
public static long getLong () { return Long.MAX_VALUE; }
|
||||
public static double getDouble () { return Double.MAX_VALUE; }
|
||||
public static String getString () { return "a string"; }
|
||||
public static List<?> getList () { return List.of("element"); }
|
||||
|
||||
public static boolean getBoolean(boolean v1, boolean v2) { return v1 || v2; }
|
||||
public static char getChar (char v1, char v2) { return (char)(v1 ^ v2); }
|
||||
public static short getShort (short v1, short v2) { return (short)(v1 ^ v2); }
|
||||
public static byte getByte (byte v1, byte v2) { return (byte)(v1 ^ v2); }
|
||||
public static int getInt (int v1, int v2) { return v1 ^ v2; }
|
||||
public static float getFloat (float v1, float v2) { return v1 * v2; }
|
||||
public static long getLong (long v1, long v2) { return v1 ^ v2; }
|
||||
public static double getDouble (double v1, double v2) { return v1 * v2; }
|
||||
public static String getString (String v1, String v2) { return v1 + v2; }
|
||||
public static List<?> getList (List<?> v1, List<?> v2) { return List.of(v1, v2); }
|
||||
// @formatter:on
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2021, 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
|
||||
@ -33,6 +33,17 @@
|
||||
|
||||
package jdk.vm.ci.runtime.test;
|
||||
|
||||
import static jdk.vm.ci.meta.MetaUtil.toInternalName;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import jdk.vm.ci.meta.DeoptimizationAction;
|
||||
import jdk.vm.ci.meta.DeoptimizationReason;
|
||||
import jdk.vm.ci.meta.JavaConstant;
|
||||
@ -42,16 +53,6 @@ import jdk.vm.ci.meta.ResolvedJavaField;
|
||||
import jdk.vm.ci.meta.ResolvedJavaMethod;
|
||||
import jdk.vm.ci.meta.ResolvedJavaType;
|
||||
import jdk.vm.ci.meta.Signature;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import static jdk.vm.ci.meta.MetaUtil.toInternalName;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* Tests for {@link MetaAccessProvider}.
|
||||
@ -117,7 +118,7 @@ public class TestMetaAccessProvider extends TypeUniverse {
|
||||
assertEquals("Unexpected javaType: " + result[counter] + " while expecting of class: " + aClass, result[counter].toClassName(), aClass.getName());
|
||||
}
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = NullPointerException.class)
|
||||
@ -187,6 +188,9 @@ public class TestMetaAccessProvider extends TypeUniverse {
|
||||
public void getMemorySizeTest() {
|
||||
for (ConstantValue cv : constants()) {
|
||||
JavaConstant c = cv.value;
|
||||
if (c.getJavaKind() == JavaKind.Illegal) {
|
||||
continue;
|
||||
}
|
||||
long memSize = metaAccess.getMemorySize(c);
|
||||
if (c.isNull()) {
|
||||
assertEquals("Expected size = 0 for null", memSize, 0L);
|
||||
|
Loading…
Reference in New Issue
Block a user