mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 07:14:30 +02:00
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
10 changed files with 391 additions and 31 deletions
|
@ -505,10 +505,11 @@ C2V_END
|
||||||
|
|
||||||
C2V_VMENTRY_0(jboolean, isCompilable,(JNIEnv* env, jobject, jobject jvmci_method))
|
C2V_VMENTRY_0(jboolean, isCompilable,(JNIEnv* env, jobject, jobject jvmci_method))
|
||||||
Method* method = JVMCIENV->asMethod(jvmci_method);
|
Method* method = JVMCIENV->asMethod(jvmci_method);
|
||||||
ConstantPool* cp = method->constMethod()->constants();
|
// Skip redefined methods
|
||||||
assert(cp != NULL, "npe");
|
if (method->is_old()) {
|
||||||
// don't inline method when constant pool contains a CONSTANT_Dynamic
|
return false;
|
||||||
return !method->is_not_compilable(CompLevel_full_optimization) && !cp->has_dynamic_constant();
|
}
|
||||||
|
return !method->is_not_compilable(CompLevel_full_optimization);
|
||||||
C2V_END
|
C2V_END
|
||||||
|
|
||||||
C2V_VMENTRY_0(jboolean, hasNeverInlineDirective,(JNIEnv* env, jobject, jobject jvmci_method))
|
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))
|
C2V_VMENTRY_NULL(jobject, resolvePossiblyCachedConstantInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index))
|
||||||
constantPoolHandle cp(THREAD, JVMCIENV->asConstantPool(jvmci_constant_pool));
|
constantPoolHandle cp(THREAD, JVMCIENV->asConstantPool(jvmci_constant_pool));
|
||||||
oop result = cp->resolve_possibly_cached_constant_at(index, CHECK_NULL);
|
oop obj = cp->resolve_possibly_cached_constant_at(index, CHECK_NULL);
|
||||||
return JVMCIENV->get_jobject(JVMCIENV->get_object_constant(result));
|
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_END
|
||||||
|
|
||||||
C2V_VMENTRY_0(jint, lookupNameAndTypeRefIndexInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index))
|
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 "lookupAppendixInPool", CC "(" HS_CONSTANT_POOL "I)" OBJECTCONSTANT, FN_PTR(lookupAppendixInPool)},
|
||||||
{CC "lookupMethodInPool", CC "(" HS_CONSTANT_POOL "IB)" HS_RESOLVED_METHOD, FN_PTR(lookupMethodInPool)},
|
{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 "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 "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 "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)},
|
{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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -245,6 +245,7 @@
|
||||||
int_field(BytecodePosition, bci) \
|
int_field(BytecodePosition, bci) \
|
||||||
end_class \
|
end_class \
|
||||||
start_class(JavaConstant, jdk_vm_ci_meta_JavaConstant) \
|
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;") \
|
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, 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)) \
|
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, Char, "Ljdk/vm/ci/meta/JavaKind;") \
|
||||||
static_object_field(JavaKind, Short, "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, 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, Long, "Ljdk/vm/ci/meta/JavaKind;") \
|
||||||
|
static_object_field(JavaKind, Double, "Ljdk/vm/ci/meta/JavaKind;") \
|
||||||
end_class \
|
end_class \
|
||||||
start_class(ValueKind, jdk_vm_ci_meta_ValueKind) \
|
start_class(ValueKind, jdk_vm_ci_meta_ValueKind) \
|
||||||
object_field(ValueKind, platformKind, "Ljdk/vm/ci/meta/PlatformKind;") \
|
object_field(ValueKind, platformKind, "Ljdk/vm/ci/meta/PlatformKind;") \
|
||||||
|
|
|
@ -430,6 +430,7 @@
|
||||||
declare_constant(JVM_CONSTANT_MethodHandle) \
|
declare_constant(JVM_CONSTANT_MethodHandle) \
|
||||||
declare_constant(JVM_CONSTANT_MethodType) \
|
declare_constant(JVM_CONSTANT_MethodType) \
|
||||||
declare_constant(JVM_CONSTANT_InvokeDynamic) \
|
declare_constant(JVM_CONSTANT_InvokeDynamic) \
|
||||||
|
declare_constant(JVM_CONSTANT_Dynamic) \
|
||||||
declare_constant(JVM_CONSTANT_Module) \
|
declare_constant(JVM_CONSTANT_Module) \
|
||||||
declare_constant(JVM_CONSTANT_Package) \
|
declare_constant(JVM_CONSTANT_Package) \
|
||||||
declare_constant(JVM_CONSTANT_ExternalMax) \
|
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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -215,11 +215,11 @@ final class CompilerToVM {
|
||||||
* constant pool cache first.
|
* constant pool cache first.
|
||||||
*
|
*
|
||||||
* The behavior of this method is undefined if {@code cpi} does not denote one of the following
|
* 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},
|
* entry types: {@code JVM_CONSTANT_Dynamic}, {@code JVM_CONSTANT_String},
|
||||||
* {@code JVM_CONSTANT_MethodHandleInError}, {@code JVM_CONSTANT_MethodType} and
|
* {@code JVM_CONSTANT_MethodHandle}, {@code JVM_CONSTANT_MethodHandleInError},
|
||||||
* {@code JVM_CONSTANT_MethodTypeInError}.
|
* {@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
|
* 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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* 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 jvmMethodType = add(new JvmConstant(c.jvmConstantMethodType, "MethodType"));
|
||||||
final JvmConstant jvmMethodTypeInError = add(new JvmConstant(c.jvmConstantMethodTypeInError, "MethodTypeInError"));
|
final JvmConstant jvmMethodTypeInError = add(new JvmConstant(c.jvmConstantMethodTypeInError, "MethodTypeInError"));
|
||||||
final JvmConstant jvmInvokeDynamic = add(new JvmConstant(c.jvmConstantInvokeDynamic, "InvokeDynamic"));
|
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) {
|
private JvmConstant add(JvmConstant constant) {
|
||||||
table[indexOf(constant.tag)] = constant;
|
table[indexOf(constant.tag)] = constant;
|
||||||
|
@ -545,6 +547,8 @@ public final class HotSpotConstantPool implements ConstantPool, MetaspaceHandleO
|
||||||
case "MethodHandleInError":
|
case "MethodHandleInError":
|
||||||
case "MethodType":
|
case "MethodType":
|
||||||
case "MethodTypeInError":
|
case "MethodTypeInError":
|
||||||
|
case "Dynamic":
|
||||||
|
case "DynamicInError":
|
||||||
return compilerToVM().resolvePossiblyCachedConstantInPool(this, cpi);
|
return compilerToVM().resolvePossiblyCachedConstantInPool(this, cpi);
|
||||||
default:
|
default:
|
||||||
throw new JVMCIError("Unknown constant pool tag %s", tag);
|
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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* 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 jvmConstantMethodHandleInError = getConstant("JVM_CONSTANT_MethodHandleInError", Integer.class);
|
||||||
final int jvmConstantMethodType = getConstant("JVM_CONSTANT_MethodType", Integer.class);
|
final int jvmConstantMethodType = getConstant("JVM_CONSTANT_MethodType", Integer.class);
|
||||||
final int jvmConstantMethodTypeInError = getConstant("JVM_CONSTANT_MethodTypeInError", 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 jvmConstantInvokeDynamic = getConstant("JVM_CONSTANT_InvokeDynamic", Integer.class);
|
||||||
|
|
||||||
final int jvmConstantExternalMax = getConstant("JVM_CONSTANT_ExternalMax", 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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* 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 DOUBLE_1 = new PrimitiveConstant(JavaKind.Double, Double.doubleToRawLongBits(1.0D));
|
||||||
PrimitiveConstant TRUE = new PrimitiveConstant(JavaKind.Boolean, 1L);
|
PrimitiveConstant TRUE = new PrimitiveConstant(JavaKind.Boolean, 1L);
|
||||||
PrimitiveConstant FALSE = new PrimitiveConstant(JavaKind.Boolean, 0L);
|
PrimitiveConstant FALSE = new PrimitiveConstant(JavaKind.Boolean, 0L);
|
||||||
|
PrimitiveConstant ILLEGAL = new PrimitiveConstant(JavaKind.Illegal, 0);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the Java kind of this constant.
|
* Returns the Java kind of this constant.
|
||||||
|
@ -329,7 +330,7 @@ public interface JavaConstant extends Constant, JavaValue {
|
||||||
}
|
}
|
||||||
|
|
||||||
static PrimitiveConstant forIllegal() {
|
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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -473,7 +473,7 @@ public enum JavaKind {
|
||||||
case Long:
|
case Long:
|
||||||
return 64;
|
return 64;
|
||||||
default:
|
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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -33,6 +33,17 @@
|
||||||
|
|
||||||
package jdk.vm.ci.runtime.test;
|
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.DeoptimizationAction;
|
||||||
import jdk.vm.ci.meta.DeoptimizationReason;
|
import jdk.vm.ci.meta.DeoptimizationReason;
|
||||||
import jdk.vm.ci.meta.JavaConstant;
|
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.ResolvedJavaMethod;
|
||||||
import jdk.vm.ci.meta.ResolvedJavaType;
|
import jdk.vm.ci.meta.ResolvedJavaType;
|
||||||
import jdk.vm.ci.meta.Signature;
|
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}.
|
* Tests for {@link MetaAccessProvider}.
|
||||||
|
@ -187,6 +188,9 @@ public class TestMetaAccessProvider extends TypeUniverse {
|
||||||
public void getMemorySizeTest() {
|
public void getMemorySizeTest() {
|
||||||
for (ConstantValue cv : constants()) {
|
for (ConstantValue cv : constants()) {
|
||||||
JavaConstant c = cv.value;
|
JavaConstant c = cv.value;
|
||||||
|
if (c.getJavaKind() == JavaKind.Illegal) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
long memSize = metaAccess.getMemorySize(c);
|
long memSize = metaAccess.getMemorySize(c);
|
||||||
if (c.isNull()) {
|
if (c.isNull()) {
|
||||||
assertEquals("Expected size = 0 for null", memSize, 0L);
|
assertEquals("Expected size = 0 for null", memSize, 0L);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue