From 408987e1ca9a42db8019b1bd7e52f85607975dde Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Mon, 31 Jul 2023 08:35:31 +0000 Subject: [PATCH 01/11] 8313307: java/util/Formatter/Padding.java fails on some Locales Reviewed-by: jlu, naoto --- test/jdk/java/util/Formatter/Padding.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/jdk/java/util/Formatter/Padding.java b/test/jdk/java/util/Formatter/Padding.java index 982b6967928..5f0e7f0e201 100644 --- a/test/jdk/java/util/Formatter/Padding.java +++ b/test/jdk/java/util/Formatter/Padding.java @@ -29,6 +29,8 @@ * @run junit Padding */ +import java.util.Locale; + import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; @@ -307,7 +309,7 @@ static Arguments[] padding() { @ParameterizedTest @MethodSource void padding(String expected, String format, Object value) { - assertEquals(expected, String.format(format, value)); + assertEquals(expected, String.format(Locale.US, format, value)); } } From b60e0adad6c2a4b8cf2709f810e185ad62777311 Mon Sep 17 00:00:00 2001 From: Matias Saavedra Silva Date: Mon, 31 Jul 2023 13:44:38 +0000 Subject: [PATCH 02/11] 8313207: Remove MetaspaceShared::_has_error_classes Reviewed-by: ccheung, iklam --- src/hotspot/share/cds/metaspaceShared.cpp | 3 --- src/hotspot/share/cds/metaspaceShared.hpp | 1 - 2 files changed, 4 deletions(-) diff --git a/src/hotspot/share/cds/metaspaceShared.cpp b/src/hotspot/share/cds/metaspaceShared.cpp index 17ce20020f3..6e24b70d782 100644 --- a/src/hotspot/share/cds/metaspaceShared.cpp +++ b/src/hotspot/share/cds/metaspaceShared.cpp @@ -87,7 +87,6 @@ ReservedSpace MetaspaceShared::_symbol_rs; VirtualSpace MetaspaceShared::_symbol_vs; -bool MetaspaceShared::_has_error_classes; bool MetaspaceShared::_archive_loading_failed = false; bool MetaspaceShared::_remapped_readwrite = false; void* MetaspaceShared::_shared_metaspace_static_top = nullptr; @@ -731,7 +730,6 @@ void MetaspaceShared::preload_classes(TRAPS) { } log_info(cds)("Loading classes to share ..."); - _has_error_classes = false; int class_count = ClassListParser::parse_classlist(classlist_path, ClassListParser::_parse_all, CHECK); if (ExtraSharedClassListFile) { @@ -814,7 +812,6 @@ bool MetaspaceShared::try_link_class(JavaThread* current, InstanceKlass* ik) { ik->external_name()); CLEAR_PENDING_EXCEPTION; SystemDictionaryShared::set_class_has_failed_verification(ik); - _has_error_classes = true; } ik->compute_has_loops_flag_for_methods(); BytecodeVerificationLocal = saved; diff --git a/src/hotspot/share/cds/metaspaceShared.hpp b/src/hotspot/share/cds/metaspaceShared.hpp index d714f3ae95e..c0879e083e4 100644 --- a/src/hotspot/share/cds/metaspaceShared.hpp +++ b/src/hotspot/share/cds/metaspaceShared.hpp @@ -47,7 +47,6 @@ enum MapArchiveResult { class MetaspaceShared : AllStatic { static ReservedSpace _symbol_rs; // used only during -Xshare:dump static VirtualSpace _symbol_vs; // used only during -Xshare:dump - static bool _has_error_classes; static bool _archive_loading_failed; static bool _remapped_readwrite; static void* _shared_metaspace_static_top; From 3671d83c87302ead09d4ebce9cb85bdd803a0c20 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Mon, 31 Jul 2023 14:57:28 +0000 Subject: [PATCH 03/11] 8313252: Java_sun_awt_windows_ThemeReader_paintBackground release resources in early returns Reviewed-by: clanger --- src/java.desktop/windows/native/libawt/windows/ThemeReader.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/java.desktop/windows/native/libawt/windows/ThemeReader.cpp b/src/java.desktop/windows/native/libawt/windows/ThemeReader.cpp index 4bbeb9a7937..08e03d00959 100644 --- a/src/java.desktop/windows/native/libawt/windows/ThemeReader.cpp +++ b/src/java.desktop/windows/native/libawt/windows/ThemeReader.cpp @@ -421,6 +421,7 @@ JNIEXPORT void JNICALL Java_sun_awt_windows_ThemeReader_paintBackground NULL, 0); if (hDibSection == NULL) { DTRACE_PRINTLN("Error creating DIB section"); + DeleteDC(memDC); ReleaseDC(NULL,defaultDC); return; } From 97b688340e2adce8e5f6abf7c3f5cb41e71afc33 Mon Sep 17 00:00:00 2001 From: Qing Xiao Date: Mon, 31 Jul 2023 15:03:05 +0000 Subject: [PATCH 04/11] 8295059: test/langtools/tools/javap 12 test classes use com.sun.tools.classfile library Reviewed-by: asotona --- test/langtools/tools/javap/T6716452.java | 68 ++-- .../tools/javap/TestClassNameWarning.java | 30 +- .../javap/classfile/6888367/T6888367.java | 361 ++++++++++-------- .../tools/javap/classfile/T6887895.java | 49 ++- .../typeAnnotations/JSR175Annotations.java | 75 ++-- .../tools/javap/typeAnnotations/NewArray.java | 68 ++-- .../tools/javap/typeAnnotations/Presence.java | 139 +++---- .../javap/typeAnnotations/PresenceInner.java | 109 ++---- .../javap/typeAnnotations/TypeCasts.java | 63 +-- .../javap/typeAnnotations/Visibility.java | 51 ++- .../javap/typeAnnotations/Wildcards.java | 101 ++--- 11 files changed, 523 insertions(+), 591 deletions(-) diff --git a/test/langtools/tools/javap/T6716452.java b/test/langtools/tools/javap/T6716452.java index 83e5612d119..bba48e9eb03 100644 --- a/test/langtools/tools/javap/T6716452.java +++ b/test/langtools/tools/javap/T6716452.java @@ -24,11 +24,18 @@ /* * @test 6716452 * @summary need a method to get an index of an attribute - * @modules jdk.jdeps/com.sun.tools.classfile + * @modules java.base/jdk.internal.classfile + * java.base/jdk.internal.classfile.attribute + * java.base/jdk.internal.classfile.constantpool + * java.base/jdk.internal.classfile.instruction + * java.base/jdk.internal.classfile.components */ import java.io.*; -import com.sun.tools.classfile.*; +import java.nio.file.Files; + +import jdk.internal.classfile.*; +import jdk.internal.classfile.attribute.*; public class T6716452 { public static void main(String[] args) throws Exception { @@ -38,49 +45,44 @@ public static void main(String[] args) throws Exception { public void run() throws Exception { File javaFile = writeTestFile(); File classFile = compileTestFile(javaFile); - - ClassFile cf = ClassFile.read(classFile); - for (Method m: cf.methods) { - test(cf, m); + ClassModel cm = Classfile.of().parse(classFile.toPath()); + for (MethodModel mm: cm.methods()) { + test(mm); } if (errors > 0) throw new Exception(errors + " errors found"); } - void test(ClassFile cf, Method m) { - test(cf, m, Attribute.Code, Code_attribute.class); - test(cf, m, Attribute.Exceptions, Exceptions_attribute.class); + void test(MethodModel mm) { + test(mm, Attributes.CODE, CodeAttribute.class); + test(mm, Attributes.EXCEPTIONS, ExceptionsAttribute.class); } - // test the result of Attributes.getIndex according to expectations + // test the result of MethodModel.findAttribute, MethodModel.attributes().indexOf() according to expectations // encoded in the method's name - void test(ClassFile cf, Method m, String name, Class c) { - int index = m.attributes.getIndex(cf.constant_pool, name); - try { - String m_name = m.getName(cf.constant_pool); - System.err.println("Method " + m_name + " name:" + name + " index:" + index + " class: " + c); - boolean expect = (m_name.equals("") && name.equals("Code")) - || (m_name.indexOf(name) != -1); - boolean found = (index != -1); - if (expect) { - if (found) { - Attribute attr = m.attributes.get(index); - if (!c.isAssignableFrom(attr.getClass())) { - error(m + ": unexpected attribute found," - + " expected " + c.getName() - + " found " + attr.getClass().getName()); - } - } else { - error(m + ": expected attribute " + name + " not found"); + > void test(MethodModel mm, AttributeMapper attr, Class c) { + Attribute attr_instance = mm.findAttribute(attr).orElse(null); + int index = mm.attributes().indexOf(attr_instance); + String mm_name = mm.methodName().stringValue(); + System.err.println("Method " + mm_name + " name:" + attr.name() + " index:" + index + " class: " + c); + boolean expect = (mm_name.equals("") && attr.name().equals("Code")) + || (mm_name.contains(attr.name())); + boolean found = (index != -1); + if (expect) { + if (found) { + if (!c.isAssignableFrom(mm.attributes().get(index).getClass())) { + error(mm + ": unexpected attribute found," + + " expected " + c.getName() + + " found " + mm.attributes().get(index).attributeName()); } } else { - if (found) { - error(m + ": unexpected attribute " + name); - } + error(mm + ": expected attribute " + attr.name() + " not found"); + } + } else { + if (found) { + error(mm + ": unexpected attribute " + attr.name()); } - } catch (ConstantPoolException e) { - error(m + ": " + e); } } diff --git a/test/langtools/tools/javap/TestClassNameWarning.java b/test/langtools/tools/javap/TestClassNameWarning.java index 20e43f9f0c1..992f4b4c505 100644 --- a/test/langtools/tools/javap/TestClassNameWarning.java +++ b/test/langtools/tools/javap/TestClassNameWarning.java @@ -29,12 +29,17 @@ * @modules * jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.main - * jdk.jdeps/com.sun.tools.classfile * jdk.jdeps/com.sun.tools.javap + * java.base/jdk.internal.classfile + * java.base/jdk.internal.classfile.attribute + * java.base/jdk.internal.classfile.constantpool + * java.base/jdk.internal.classfile.instruction + * java.base/jdk.internal.classfile.components * @build toolbox.JavacTask toolbox.JavapTask toolbox.ToolBox toolbox.TestRunner * @run main TestClassNameWarning */ +import java.lang.constant.ClassDesc; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -43,9 +48,8 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; -import com.sun.tools.classfile.ClassFile; -import com.sun.tools.classfile.ClassWriter; +import jdk.internal.classfile.*; import toolbox.JavacTask; import toolbox.JavapTask; import toolbox.Task; @@ -140,7 +144,7 @@ public void testLegacyModuleInfo(Path base) throws Exception { byte[] replaceBytes = "module-info".getBytes("UTF-8"); for (int i = 0; i < bytes.length - searchBytes.length; i++) { if (Arrays.equals(bytes, i, i + searchBytes.length, - searchBytes, 0, searchBytes.length)) { + searchBytes, 0, searchBytes.length)) { System.arraycopy(replaceBytes, 0, bytes, i, replaceBytes.length); } } @@ -172,14 +176,15 @@ public void testNoNameClass(Path base) throws Exception { .files(tb.findJavaFiles(src)) .run() .writeAll(); - - ClassFile cf = ClassFile.read(classes.resolve("A.class")); - ClassFile cf2 = new ClassFile( - cf.magic, cf.minor_version, cf.major_version, cf.constant_pool, - cf.access_flags, - 0, // this_class, - cf.super_class, cf.interfaces, cf.fields, cf.methods, cf.attributes); - new ClassWriter().write(cf2, Files.newOutputStream(classes.resolve("Z.class"))); + ClassModel cm = Classfile.of().parse(classes.resolve("A.class")); + Classfile.of().buildTo( + classes.resolve("Z.class"), + ClassDesc.of("0"), cb -> { + for (ClassElement ce : cm) { + cb.with(ce); + } + } + ); List log = new JavapTask(tb) .classpath(classes.toString()) @@ -238,4 +243,3 @@ private void checkOutput(List log, boolean expect, String regex) { } } } - diff --git a/test/langtools/tools/javap/classfile/6888367/T6888367.java b/test/langtools/tools/javap/classfile/6888367/T6888367.java index 232f1e080a4..50a8e67ee38 100644 --- a/test/langtools/tools/javap/classfile/6888367/T6888367.java +++ b/test/langtools/tools/javap/classfile/6888367/T6888367.java @@ -24,21 +24,23 @@ import java.io.*; import java.net.*; import java.util.*; +import java.lang.constant.*; +import java.nio.file.Paths; -import com.sun.tools.classfile.*; -import com.sun.tools.classfile.Type.ArrayType; -import com.sun.tools.classfile.Type.ClassSigType; -import com.sun.tools.classfile.Type.ClassType; -import com.sun.tools.classfile.Type.MethodType; -import com.sun.tools.classfile.Type.SimpleType; -import com.sun.tools.classfile.Type.TypeParamType; -import com.sun.tools.classfile.Type.WildcardType; +import jdk.internal.classfile.*; +import jdk.internal.classfile.attribute.*; +import jdk.internal.classfile.constantpool.*; /* * @test * @bug 6888367 * @summary classfile library parses signature attributes incorrectly - * @modules jdk.jdeps/com.sun.tools.classfile + * @modules java.base/jdk.internal.classfile + * java.base/jdk.internal.classfile.attribute + * java.base/jdk.internal.classfile.constantpool + * java.base/jdk.internal.classfile.instruction + * java.base/jdk.internal.classfile.components + * java.base/jdk.internal.classfile.impl */ /* @@ -61,99 +63,108 @@ public static void main(String... args) throws Exception { } public void run() throws Exception { - ClassFile cf = getClassFile("Test"); + ClassModel cm = getClassFile("Test"); - testFields(cf); - testMethods(cf); - testInnerClasses(cf); // recursive + testFields(cm); + testMethods(cm); + testInnerClasses(cm); // recursive if (errors > 0) throw new Exception(errors + " errors found"); } - void testFields(ClassFile cf) throws Exception { - String cn = cf.getName(); - ConstantPool cp = cf.constant_pool; - for (Field f: cf.fields) { - test("field " + cn + "." + f.getName(cp), f.descriptor, f.attributes, cp); + void testFields(ClassModel cm) throws Exception { + String cn = cm.thisClass().name().stringValue(); + for (FieldModel fm: cm.fields()) { + test("field " + cn + "." + fm.fieldName(), fm.fieldTypeSymbol(), fm); } } - void testMethods(ClassFile cf) throws Exception { - String cn = cf.getName(); - ConstantPool cp = cf.constant_pool; - for (Method m: cf.methods) { - test("method " + cn + "." + m.getName(cp), m.descriptor, m.attributes, cp); + void testMethods(ClassModel cm) throws Exception { + String cn = cm.thisClass().name().stringValue(); + for (MethodModel mm: cm.methods()) { + test("method " + cn + "." + mm.methodName(), mm.methodTypeSymbol(), mm); } } - void testInnerClasses(ClassFile cf) throws Exception { - ConstantPool cp = cf.constant_pool; - InnerClasses_attribute ic = - (InnerClasses_attribute) cf.attributes.get(Attribute.InnerClasses); - for (InnerClasses_attribute.Info info: ic.classes) { - String outerClassName = cp.getClassInfo(info.outer_class_info_index).getName(); - if (!outerClassName.equals(cf.getName())) { + void testInnerClasses(ClassModel cm) throws Exception { + InnerClassesAttribute ic = + cm.findAttribute(Attributes.INNER_CLASSES).orElse(null); + assert ic != null; + for (InnerClassInfo info: ic.classes()) { + ClassEntry outerClass = info.outerClass().orElse(null); + if (outerClass == null || !outerClass.name().equalsString(cm.getClass().getName())) { continue; } - String innerClassName = cp.getClassInfo(info.inner_class_info_index).getName(); - ClassFile icf = getClassFile(innerClassName); - test("class " + innerClassName, null, icf.attributes, icf.constant_pool); - testInnerClasses(icf); + String innerClassName = info.innerClass().asInternalName(); + ClassModel icm = getClassFile(innerClassName); + test("class " + innerClassName, null, icm); + testInnerClasses(icm); } } - void test(String name, Descriptor desc, Attributes attrs, ConstantPool cp) - throws Exception { - AnnotValues d = getDescValue(attrs, cp); - AnnotValues s = getSigValue(attrs, cp); + void test(String name, ConstantDesc desc, AttributedElement m) { + AnnotValues d = getDescValue(m); + AnnotValues s = getSigValue(m); if (d == null && s == null) // not a test field or method if no @Desc or @Sig given return; System.err.println(name); - - if (desc != null) { - System.err.println(" descriptor: " + desc.getValue(cp)); - checkEqual(d.raw, desc.getValue(cp)); - Type dt = new Signature(desc.index).getType(cp); - checkEqual(d.type, tp.print(dt)); - } - - Signature_attribute sa = (Signature_attribute) attrs.get(Attribute.Signature); + SignatureAttribute sa = m.findAttribute(Attributes.SIGNATURE).orElse(null); if (sa != null) - System.err.println(" signature: " + sa.getSignature(cp)); - - if (s != null || sa != null) { - if (s != null && sa != null) { - checkEqual(s.raw, sa.getSignature(cp)); - Type st = new Signature(sa.signature_index).getType(cp); - checkEqual(s.type, tp.print(st)); - } else if (s != null) - error("@Sig annotation found but not Signature attribute"); - else - error("Signature attribute found but no @Sig annotation"); + System.err.println(" signature: " + sa.signature()); + + switch (desc) { + case ClassDesc cDesc -> { + System.err.println(" descriptor: " + cDesc.descriptorString()); + checkEqual(d.raw, cDesc.descriptorString()); + Signature dt = Signature.of(cDesc); + checkEqual(d.type, tp.print(dt)); + if (s != null || sa != null) { + if (s != null && sa != null) { + checkEqual(s.raw, sa.signature().stringValue()); + Signature st = Signature.parseFrom(sa.signature().stringValue()); + checkEqual(s.type, tp.print(st)); + } else if (s != null) + error("@Sig annotation found but not Signature attribute"); + else + error("Signature attribute found but no @Sig annotation"); + } + } + case MethodTypeDesc mDesc -> { + System.err.println(" descriptor: " + mDesc.descriptorString()); + checkEqual(d.raw, mDesc.descriptorString()); + MethodSignature mdt = MethodSignature.of(mDesc); + checkEqual(d.type, tp.print(mdt)); + if (s != null || sa != null) { + if (s != null && sa != null) { + checkEqual(s.raw, sa.signature().stringValue()); + MethodSignature mst = MethodSignature.parseFrom(sa.signature().stringValue()); + checkEqual(s.type, tp.print(mst)); + } else if (s != null) + error("@Sig annotation found but not Signature attribute"); + else + error("Signature attribute found but no @Sig annotation"); + } + } + default -> throw new AssertionError(); } - System.err.println(); } - ClassFile getClassFile(String name) throws IOException, ConstantPoolException { - URL url = getClass().getResource(name + ".class"); - InputStream in = url.openStream(); - try { - return ClassFile.read(in); - } finally { - in.close(); - } + ClassModel getClassFile(String name) throws IOException, URISyntaxException { + URL rsc = getClass().getResource(name + ".class"); + assert rsc != null; + return Classfile.of().parse(Paths.get(rsc.toURI())); } - AnnotValues getDescValue(Attributes attrs, ConstantPool cp) throws Exception { - return getAnnotValues(Desc.class.getName(), attrs, cp); + AnnotValues getDescValue(AttributedElement m) { + return getAnnotValues(Desc.class.getName(), m); } - AnnotValues getSigValue(Attributes attrs, ConstantPool cp) throws Exception { - return getAnnotValues(Sig.class.getName(), attrs, cp); + AnnotValues getSigValue(AttributedElement m) { + return getAnnotValues(Sig.class.getName(), m); } static class AnnotValues { @@ -165,20 +176,14 @@ static class AnnotValues { final String type; } - AnnotValues getAnnotValues(String annotName, Attributes attrs, ConstantPool cp) - throws Exception { - RuntimeInvisibleAnnotations_attribute annots = - (RuntimeInvisibleAnnotations_attribute)attrs.get(Attribute.RuntimeInvisibleAnnotations); + AnnotValues getAnnotValues(String annotName, AttributedElement m) { + RuntimeInvisibleAnnotationsAttribute annots = m.findAttribute(Attributes.RUNTIME_INVISIBLE_ANNOTATIONS).orElse(null); if (annots != null) { - for (Annotation a: annots.annotations) { - if (cp.getUTF8Value(a.type_index).equals("L" + annotName + ";")) { - Annotation.Primitive_element_value pv0 = - (Annotation.Primitive_element_value) a.element_value_pairs[0].value; - Annotation.Primitive_element_value pv1 = - (Annotation.Primitive_element_value) a.element_value_pairs[1].value; - return new AnnotValues( - cp.getUTF8Value(pv0.const_value_index), - cp.getUTF8Value(pv1.const_value_index)); + for (Annotation a: annots.annotations()) { + if (a.classSymbol().descriptorString().equals("L" + annotName + ";")) { + String pv0 = ((AnnotationValue.OfString) a.elements().get(0).value()).stringValue(); + String pv1 = ((AnnotationValue.OfString) a.elements().get(1).value()).stringValue(); + return new AnnotValues(pv0, pv1); } } } @@ -187,7 +192,7 @@ AnnotValues getAnnotValues(String annotName, Attributes attrs, ConstantPool cp) } void checkEqual(String expect, String found) { - if (!(expect == null ? found == null : expect.equals(found))) { + if (!(Objects.equals(expect, found))) { System.err.println("expected: " + expect); System.err.println(" found: " + found); error("unexpected values found"); @@ -203,96 +208,128 @@ void error(String msg) { TypePrinter tp = new TypePrinter(); - class TypePrinter implements Type.Visitor { - String print(Type t) { - return t == null ? null : t.accept(this, null); + class TypePrinter { + String print(T t) { + switch (t) { + case Signature.BaseTypeSig type -> { + return visitSimpleType(type); + } + case Signature.ArrayTypeSig type -> { + return visitArrayType(type); + } + case Signature.ClassTypeSig type -> { + return visitClassType(type); + } + case ClassSignature type -> { + return visitClassSigType(type); + } + case MethodSignature type -> { + return visitMethodType(type); + } + case Signature.TypeVarSig type -> { + return "S{" + type.identifier() + "}"; //Consider the TypeVarSig as Simple Type + } + default -> { + return null; + } + } } - String print(String pre, List ts, String post) { + String print(String pre, List ts, String post) { if (ts == null) return null; StringBuilder sb = new StringBuilder(); sb.append(pre); String sep = ""; - for (Type t: ts) { + for (T t: ts) { sb.append(sep); - sb.append(print(t)); + switch (t) { + case Signature sig -> sb.append(print(sig)); + case Signature.TypeParam pSig -> sb.append(visitTypeParamType(pSig)); + case Signature.TypeArg aSig -> sb.append(visitWildcardType(aSig)); + default -> throw new AssertionError(); + } sep = ","; } sb.append(post); return sb.toString(); } - public String visitSimpleType(SimpleType type, Void p) { - return "S{" + type.name + "}"; + public String visitSimpleType(Signature.BaseTypeSig type) { + return "S{" + type.baseType() + "}"; } - public String visitArrayType(ArrayType type, Void p) { - return "A{" + print(type.elemType) + "}"; + public String visitArrayType(Signature.ArrayTypeSig type) { + return "A{" + print(type.componentSignature()) + "}"; } - public String visitMethodType(MethodType type, Void p) { + public String visitMethodType(MethodSignature type) { StringBuilder sb = new StringBuilder(); sb.append("M{"); - if (type.typeParamTypes != null) - sb.append(print("<", type.typeParamTypes, ">")); - sb.append(print(type.returnType)); - sb.append(print("(", type.paramTypes, ")")); - if (type.throwsTypes != null) - sb.append(print("", type.throwsTypes, "")); + if (!type.typeParameters().isEmpty()) + sb.append(print("<", type.typeParameters(), ">")); + sb.append(print(type.result())); + sb.append(print("(", type.arguments(), ")")); + if (!type.throwableSignatures().isEmpty()) + sb.append(print("", type.throwableSignatures(), "")); sb.append("}"); return sb.toString(); } - public String visitClassSigType(ClassSigType type, Void p) { + public String visitClassSigType(ClassSignature type) { StringBuilder sb = new StringBuilder(); sb.append("CS{"); - if (type.typeParamTypes != null) - sb.append(print("<", type.typeParamTypes, ">")); - sb.append(print(type.superclassType)); - if (type.superinterfaceTypes != null) - sb.append(print("i(", type.superinterfaceTypes, ")")); + if (!type.typeParameters().isEmpty()) + sb.append(print("<", type.typeParameters(), ">")); + sb.append(print(type.superclassSignature())); + if (!type.superinterfaceSignatures().isEmpty()) + sb.append(print("i(", type.superinterfaceSignatures(), ")")); sb.append("}"); return sb.toString(); } - public String visitClassType(ClassType type, Void p) { + public String visitClassType(Signature.ClassTypeSig type) { StringBuilder sb = new StringBuilder(); sb.append("C{"); - if (type.outerType != null) { - sb.append(print(type.outerType)); + if (type.outerType().isPresent()) { + sb.append(print(type.outerType().get())); sb.append("."); } - sb.append(type.name); - if (type.typeArgs != null) - sb.append(print("<", type.typeArgs, ">")); + sb.append(type.className()); + if (!type.typeArgs().isEmpty()) + sb.append(print("<", type.typeArgs(), ">")); sb.append("}"); return sb.toString(); } - public String visitTypeParamType(TypeParamType type, Void p) { + public String visitTypeParamType(Signature.TypeParam type) { StringBuilder sb = new StringBuilder(); sb.append("TA{"); - sb.append(type.name); - if (type.classBound != null) { + sb.append(type.identifier()); + if (type.classBound().isPresent()) { sb.append(":c"); - sb.append(print(type.classBound)); + sb.append(print(type.classBound().get())); } - if (type.interfaceBounds != null) - sb.append(print(":i", type.interfaceBounds, "")); + if (!type.interfaceBounds().isEmpty()) + sb.append(print(":i", type.interfaceBounds(), "")); sb.append("}"); return sb.toString(); } - public String visitWildcardType(WildcardType type, Void p) { - switch (type.kind) { - case UNBOUNDED: + public String visitWildcardType(Signature.TypeArg type) { + switch (type.wildcardIndicator()) { + case UNBOUNDED -> { return "W{?}"; - case EXTENDS: - return "W{e," + print(type.boundType) + "}"; - case SUPER: - return "W{s," + print(type.boundType) + "}"; - default: - throw new AssertionError(); + } + case EXTENDS -> { + return "W{e," + print(type.boundType().get()) + "}"; + } + case SUPER -> { + return "W{s," + print(type.boundType().get()) + "}"; + } + default -> { + if (type.boundType().isPresent()) return print(type.boundType().get()); + else throw new AssertionError(); + } } } @@ -317,28 +354,28 @@ class GenClss { } class Test { // fields - @Desc(d="Z", t="S{boolean}") + @Desc(d="Z", t="S{Z}") boolean z; - @Desc(d="B", t="S{byte}") + @Desc(d="B", t="S{B}") byte b; - @Desc(d="C", t="S{char}") + @Desc(d="C", t="S{C}") char c; - @Desc(d="D", t="S{double}") + @Desc(d="D", t="S{D}") double d; - @Desc(d="F", t="S{float}") + @Desc(d="F", t="S{F}") float f; - @Desc(d="I", t="S{int}") + @Desc(d="I", t="S{I}") int i; - @Desc(d="J", t="S{long}") + @Desc(d="J", t="S{J}") long l; - @Desc(d="S", t="S{short}") + @Desc(d="S", t="S{S}") short s; @Desc(d="LClss;", t="C{Clss}") @@ -347,7 +384,7 @@ class Test { @Desc(d="LIntf;", t="C{Intf}") Intf intf; - @Desc(d="[I", t="A{S{int}}") + @Desc(d="[I", t="A{S{I}}") int[] ai; @Desc(d="[LClss;", t="A{C{Clss}}") @@ -359,16 +396,16 @@ class Test { // methods, return types - @Desc(d="()V", t="M{S{void}()}") + @Desc(d="()V", t="M{S{V}()}") void mv0() { } - @Desc(d="()I", t="M{S{int}()}") + @Desc(d="()I", t="M{S{I}()}") int mi0() { return 0; } @Desc(d="()LClss;", t="M{C{Clss}()}") Clss mclss0() { return null; } - @Desc(d="()[I", t="M{A{S{int}}()}") + @Desc(d="()[I", t="M{A{S{I}}()}") int[] mai0() { return null; } @Desc(d="()[LClss;", t="M{A{C{Clss}}()}") @@ -405,57 +442,57 @@ void mv0() { } // methods, arg types - @Desc(d="(I)V", t="M{S{void}(S{int})}") + @Desc(d="(I)V", t="M{S{V}(S{I})}") void mi1(int arg) { } - @Desc(d="(LClss;)V", t="M{S{void}(C{Clss})}") + @Desc(d="(LClss;)V", t="M{S{V}(C{Clss})}") void mclss1(Clss arg) { } - @Desc(d="([I)V", t="M{S{void}(A{S{int}})}") + @Desc(d="([I)V", t="M{S{V}(A{S{I}})}") void mai1(int[] arg) { } - @Desc(d="([LClss;)V", t="M{S{void}(A{C{Clss}})}") + @Desc(d="([LClss;)V", t="M{S{V}(A{C{Clss}})}") void maClss1(Clss[] arg) { } - @Desc(d="(LGenClss;)V", t="M{S{void}(C{GenClss})}") - @Sig(s="(LGenClss;)V", t="M{S{void}(C{GenClss})}") + @Desc(d="(LGenClss;)V", t="M{S{V}(C{GenClss})}") + @Sig(s="(LGenClss;)V", t="M{S{V}(C{GenClss})}") void mgenClss1(GenClss arg) { } - @Desc(d="(LGenClss;)V", t="M{S{void}(C{GenClss})}") - @Sig(s="(LGenClss<*>;)V", t="M{S{void}(C{GenClss})}") + @Desc(d="(LGenClss;)V", t="M{S{V}(C{GenClss})}") + @Sig(s="(LGenClss<*>;)V", t="M{S{V}(C{GenClss})}") void mgenClssW1(GenClss arg) { } - @Desc(d="(LGenClss;)V", t="M{S{void}(C{GenClss})}") - @Sig(s="(LGenClss<+LClss;>;)V", t="M{S{void}(C{GenClss})}") + @Desc(d="(LGenClss;)V", t="M{S{V}(C{GenClss})}") + @Sig(s="(LGenClss<+LClss;>;)V", t="M{S{V}(C{GenClss})}") void mgenClssWExtClss1(GenClss arg) { } - @Desc(d="(LGenClss;)V", t="M{S{void}(C{GenClss})}") - @Sig(s="(LGenClss<-LClss;>;)V", t="M{S{void}(C{GenClss})}") + @Desc(d="(LGenClss;)V", t="M{S{V}(C{GenClss})}") + @Sig(s="(LGenClss<-LClss;>;)V", t="M{S{V}(C{GenClss})}") void mgenClssWSupClss1(GenClss arg) { } - @Desc(d="(Ljava/lang/Object;)V", t="M{S{void}(C{java/lang/Object})}") + @Desc(d="(Ljava/lang/Object;)V", t="M{S{V}(C{java/lang/Object})}") @Sig(s="(TT;)V", - t="M{S{void}(S{T})}") + t="M{S{V}(S{T})}") void mt1(T arg) { } - @Desc(d="(LGenClss;)V", t="M{S{void}(C{GenClss})}") + @Desc(d="(LGenClss;)V", t="M{S{V}(C{GenClss})}") @Sig(s="(LGenClss<+TT;>;)V", - t="M{S{void}(C{GenClss})}") + t="M{S{V}(C{GenClss})}") void mgenClssWExtT1(GenClss arg) { } - @Desc(d="(LGenClss;)V", t="M{S{void}(C{GenClss})}") + @Desc(d="(LGenClss;)V", t="M{S{V}(C{GenClss})}") @Sig(s="(LGenClss<-TT;>;)V", - t="M{S{void}(C{GenClss})}") + t="M{S{V}(C{GenClss})}") void mgenClssWSupT1(GenClss arg) { } // methods, throws - @Desc(d="()V", t="M{S{void}()}") + @Desc(d="()V", t="M{S{V}()}") void m_E() throws Exception { } - @Desc(d="()V", t="M{S{void}()}") + @Desc(d="()V", t="M{S{V}()}") @Sig(s="()V^TT;", - t="M{S{void}()S{T}}") + t="M{S{V}()S{T}}") void m_T() throws T { } // inner classes diff --git a/test/langtools/tools/javap/classfile/T6887895.java b/test/langtools/tools/javap/classfile/T6887895.java index e6c6437a531..cd3b41e51dd 100644 --- a/test/langtools/tools/javap/classfile/T6887895.java +++ b/test/langtools/tools/javap/classfile/T6887895.java @@ -24,15 +24,20 @@ /* * @test * @bug 6887895 - * @summary CONSTANT_Class_info getBaseName does not handle arrays of primitives correctly - * @modules jdk.jdeps/com.sun.tools.classfile + * @summary test getting constantpool elements' basename through asInternalName() API + * @modules java.base/jdk.internal.classfile + * java.base/jdk.internal.classfile.attribute + * java.base/jdk.internal.classfile.constantpool + * java.base/jdk.internal.classfile.instruction + * java.base/jdk.internal.classfile.components */ import java.io.*; import java.net.*; +import java.nio.file.Paths; import java.util.*; -import com.sun.tools.classfile.*; -import com.sun.tools.classfile.ConstantPool.*; +import jdk.internal.classfile.*; +import jdk.internal.classfile.constantpool.*; public class T6887895 { public static void main(String[] args) throws Exception { @@ -42,23 +47,22 @@ public static void main(String[] args) throws Exception { void run() throws Exception { Set found = new TreeSet(); - ClassFile cf = getClassFile("T6887895$Test.class"); - for (CPInfo cpInfo: cf.constant_pool.entries()) { - if (cpInfo instanceof CONSTANT_Class_info) { - CONSTANT_Class_info info = (CONSTANT_Class_info) cpInfo; - String name = info.getName(); - String baseName = info.getBaseName(); - System.out.println("found: " + name + " " + baseName); - if (baseName != null) - found.add(baseName); + ClassModel cm = getClassFile("T6887895$Test.class"); + ConstantPool cp = cm.constantPool(); + for (int i = 1; i < cp.entryCount(); ++i) { + if (cp.entryByIndex(i) instanceof ClassEntry ce) { + String name = ce.asInternalName(); + System.out.println("found: " + name); + if (ce.asSymbol().isClassOrInterface()) + found.add(name); } } String[] expectNames = { - "java/lang/Object", - "java/lang/String", - "T6887895", - "T6887895$Test" + "java/lang/Object", + "java/lang/String", + "T6887895", + "T6887895$Test" }; Set expect = new TreeSet(Arrays.asList(expectNames)); @@ -69,14 +73,9 @@ void run() throws Exception { } } - ClassFile getClassFile(String name) throws IOException, ConstantPoolException { - URL url = getClass().getResource(name); - InputStream in = url.openStream(); - try { - return ClassFile.read(in); - } finally { - in.close(); - } + ClassModel getClassFile(String name) throws IOException, URISyntaxException { + URL rsc = getClass().getResource(name); + return Classfile.of().parse(Paths.get(rsc.toURI())); } class Test { diff --git a/test/langtools/tools/javap/typeAnnotations/JSR175Annotations.java b/test/langtools/tools/javap/typeAnnotations/JSR175Annotations.java index a80ea9e11a3..a4ce227d2dd 100644 --- a/test/langtools/tools/javap/typeAnnotations/JSR175Annotations.java +++ b/test/langtools/tools/javap/typeAnnotations/JSR175Annotations.java @@ -22,13 +22,19 @@ */ import java.io.*; -import com.sun.tools.classfile.*; +import jdk.internal.classfile.*; +import jdk.internal.classfile.Attributes; +import jdk.internal.classfile.attribute.*; /* * @test JSR175Annotations * @bug 6843077 * @summary test that only type annotations are recorded as such in classfile - * @modules jdk.jdeps/com.sun.tools.classfile + * @modules java.base/jdk.internal.classfile + * java.base/jdk.internal.classfile.attribute + * java.base/jdk.internal.classfile.constantpool + * java.base/jdk.internal.classfile.instruction + * java.base/jdk.internal.classfile.components */ public class JSR175Annotations { @@ -40,12 +46,12 @@ public void run() throws Exception { File javaFile = writeTestFile(); File classFile = compileTestFile(javaFile); - ClassFile cf = ClassFile.read(classFile); - for (Field f : cf.fields) { - test(cf, f); + ClassModel cm = Classfile.of().parse(classFile.toPath()); + for (MethodModel mm: cm.methods()) { + test(mm); } - for (Method m: cf.methods) { - test(cf, m); + for (FieldModel fm: cm.fields()) { + test(fm); } countAnnotations(); @@ -55,45 +61,26 @@ public void run() throws Exception { System.out.println("PASSED"); } - void test(ClassFile cf, Method m) { - test(cf, m, Attribute.RuntimeVisibleTypeAnnotations, true); - test(cf, m, Attribute.RuntimeInvisibleTypeAnnotations, false); + void test(AttributedElement m) { + test(m, Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS); + test(m, Attributes.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS); } - void test(ClassFile cf, Field m) { - test(cf, m, Attribute.RuntimeVisibleTypeAnnotations, true); - test(cf, m, Attribute.RuntimeInvisibleTypeAnnotations, false); - } - - // test the result of Attributes.getIndex according to expectations - // encoded in the method's name - void test(ClassFile cf, Method m, String name, boolean visible) { - int index = m.attributes.getIndex(cf.constant_pool, name); - if (index != -1) { - Attribute attr = m.attributes.get(index); - assert attr instanceof RuntimeTypeAnnotations_attribute; - RuntimeTypeAnnotations_attribute tAttr = (RuntimeTypeAnnotations_attribute)attr; - all += tAttr.annotations.length; - if (visible) - visibles += tAttr.annotations.length; - else - invisibles += tAttr.annotations.length; - } - } - - // test the result of Attributes.getIndex according to expectations - // encoded in the method's name - void test(ClassFile cf, Field m, String name, boolean visible) { - int index = m.attributes.getIndex(cf.constant_pool, name); - if (index != -1) { - Attribute attr = m.attributes.get(index); - assert attr instanceof RuntimeTypeAnnotations_attribute; - RuntimeTypeAnnotations_attribute tAttr = (RuntimeTypeAnnotations_attribute)attr; - all += tAttr.annotations.length; - if (visible) - visibles += tAttr.annotations.length; - else - invisibles += tAttr.annotations.length; + // test the result of AttributedElement.findAttribute according to expectations + > void test(AttributedElement m, AttributeMapper attr_name) { + Attribute attr_instance = m.findAttribute(attr_name).orElse(null); + if (attr_instance != null) { + switch (attr_instance) { + case RuntimeVisibleTypeAnnotationsAttribute tAttr -> { + all += tAttr.annotations().size(); + visibles += tAttr.annotations().size(); + } + case RuntimeInvisibleTypeAnnotationsAttribute tAttr -> { + all += tAttr.annotations().size(); + invisibles += tAttr.annotations().size(); + } + default -> throw new AssertionError(); + } } } diff --git a/test/langtools/tools/javap/typeAnnotations/NewArray.java b/test/langtools/tools/javap/typeAnnotations/NewArray.java index 9becf5dbae8..e0f6bc08e85 100644 --- a/test/langtools/tools/javap/typeAnnotations/NewArray.java +++ b/test/langtools/tools/javap/typeAnnotations/NewArray.java @@ -22,17 +22,21 @@ */ import java.io.*; -import com.sun.tools.classfile.*; +import jdk.internal.classfile.*; +import jdk.internal.classfile.attribute.*; /* * @test NewArray * @bug 6843077 * @summary Test type annotations on local array are in method's code attribute. - * @modules jdk.jdeps/com.sun.tools.classfile + * @modules java.base/jdk.internal.classfile + * java.base/jdk.internal.classfile.attribute + * java.base/jdk.internal.classfile.constantpool + * java.base/jdk.internal.classfile.instruction + * java.base/jdk.internal.classfile.components */ public class NewArray { - public static void main(String[] args) throws Exception { new NewArray().run(); } @@ -41,51 +45,48 @@ public void run() throws Exception { File javaFile = writeTestFile(); File classFile = compileTestFile(javaFile); - ClassFile cf = ClassFile.read(classFile); - for (Method m: cf.methods) { - test(cf, m); + ClassModel cm = Classfile.of().parse(classFile.toPath()); + for (MethodModel mm: cm.methods()) { + test(mm); } - countAnnotations(); - if (errors > 0) throw new Exception(errors + " errors found"); System.out.println("PASSED"); } - void test(ClassFile cf, Method m) { - test(cf, m, Attribute.RuntimeVisibleTypeAnnotations, true); - test(cf, m, Attribute.RuntimeInvisibleTypeAnnotations, false); + void test(MethodModel mm) { + test(mm, Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS); + test(mm, Attributes.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS); } // test the result of Attributes.getIndex according to expectations // encoded in the method's name - void test(ClassFile cf, Method m, String name, boolean visible) { - Attribute attr = null; - Code_attribute cAttr = null; - RuntimeTypeAnnotations_attribute tAttr = null; - - int index = m.attributes.getIndex(cf.constant_pool, Attribute.Code); - if(index!= -1) { - attr = m.attributes.get(index); - assert attr instanceof Code_attribute; - cAttr = (Code_attribute)attr; - index = cAttr.attributes.getIndex(cf.constant_pool, name); - if(index!= -1) { - attr = cAttr.attributes.get(index); - assert attr instanceof RuntimeTypeAnnotations_attribute; - tAttr = (RuntimeTypeAnnotations_attribute)attr; - all += tAttr.annotations.length; - if (visible) - visibles += tAttr.annotations.length; - else - invisibles += tAttr.annotations.length; - } + > void test(MethodModel mm, AttributeMapper attr_name) { + Attribute attr_instance; + CodeAttribute cAttr; + + cAttr = mm.findAttribute(Attributes.CODE).orElse(null); + if (cAttr != null) { + attr_instance = cAttr.findAttribute(attr_name).orElse(null); + if (attr_instance != null) { + switch (attr_instance) { + case RuntimeVisibleTypeAnnotationsAttribute tAttr -> { + all += tAttr.annotations().size(); + visibles += tAttr.annotations().size(); + } + case RuntimeInvisibleTypeAnnotationsAttribute tAttr -> { + all += tAttr.annotations().size(); + invisibles += tAttr.annotations().size(); + } + default -> throw new AssertionError(); + } + } } } File writeTestFile() throws IOException { - File f = new File("Test.java"); + File f = new File("Test.java"); PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(f))); out.println("import java.lang.annotation.*;"); out.println("import java.util.*;"); @@ -133,7 +134,6 @@ void countAnnotations() { } } - int errors; int all; int visibles; diff --git a/test/langtools/tools/javap/typeAnnotations/Presence.java b/test/langtools/tools/javap/typeAnnotations/Presence.java index 72236bca7a0..9d838432bf1 100644 --- a/test/langtools/tools/javap/typeAnnotations/Presence.java +++ b/test/langtools/tools/javap/typeAnnotations/Presence.java @@ -23,14 +23,18 @@ import java.io.*; import java.lang.annotation.ElementType; - -import com.sun.tools.classfile.*; +import jdk.internal.classfile.*; +import jdk.internal.classfile.attribute.*; /* * @test Presence * @bug 6843077 * @summary test that all type annotations are present in the classfile - * @modules jdk.jdeps/com.sun.tools.classfile + * @modules java.base/jdk.internal.classfile + * java.base/jdk.internal.classfile.attribute + * java.base/jdk.internal.classfile.constantpool + * java.base/jdk.internal.classfile.instruction + * java.base/jdk.internal.classfile.components */ public class Presence { @@ -42,13 +46,13 @@ public void run() throws Exception { File javaFile = writeTestFile(); File classFile = compileTestFile(javaFile); - ClassFile cf = ClassFile.read(classFile); - test(cf); - for (Field f : cf.fields) { - test(cf, f); + ClassModel cm = Classfile.of().parse(classFile.toPath()); + test(cm); + for (FieldModel fm : cm.fields()) { + test(fm); } - for (Method m: cf.methods) { - test(cf, m); + for (MethodModel mm: cm.methods()) { + test(mm); } countAnnotations(); @@ -58,91 +62,50 @@ public void run() throws Exception { System.out.println("PASSED"); } - void test(ClassFile cf) { - test(cf, Attribute.RuntimeVisibleTypeAnnotations, true); - test(cf, Attribute.RuntimeInvisibleTypeAnnotations, false); - } - - void test(ClassFile cf, Method m) { - test(cf, m, Attribute.RuntimeVisibleTypeAnnotations, true); - test(cf, m, Attribute.RuntimeInvisibleTypeAnnotations, false); + void test(AttributedElement m) { + test(m, Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS); + test(m, Attributes.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS); } - void test(ClassFile cf, Field m) { - test(cf, m, Attribute.RuntimeVisibleTypeAnnotations, true); - test(cf, m, Attribute.RuntimeInvisibleTypeAnnotations, false); - } - - // test the result of Attributes.getIndex according to expectations - // encoded in the method's name - void test(ClassFile cf, String name, boolean visible) { - int index = cf.attributes.getIndex(cf.constant_pool, name); - if (index != -1) { - Attribute attr = cf.attributes.get(index); - assert attr instanceof RuntimeTypeAnnotations_attribute; - RuntimeTypeAnnotations_attribute tAttr = (RuntimeTypeAnnotations_attribute)attr; - all += tAttr.annotations.length; - if (visible) - visibles += tAttr.annotations.length; - else - invisibles += tAttr.annotations.length; + // test the result of AttributedElement.findAttribute according to expectations + > void test(AttributedElement m, AttributeMapper attr_name) { + Object attr_instance = m.findAttribute(attr_name).orElse(null); + if (attr_instance != null) { + switch (attr_instance) { + case RuntimeVisibleTypeAnnotationsAttribute tAttr -> { + all += tAttr.annotations().size(); + visibles += tAttr.annotations().size(); + } + case RuntimeInvisibleTypeAnnotationsAttribute tAttr -> { + all += tAttr.annotations().size(); + invisibles += tAttr.annotations().size(); + } + default -> throw new AssertionError(); + } } - } - - // test the result of Attributes.getIndex according to expectations - // encoded in the method's name - void test(ClassFile cf, Method m, String name, boolean visible) { - Attribute attr = null; - Code_attribute cAttr = null; - RuntimeTypeAnnotations_attribute tAttr = null; - - // collect annotations attributes on method - int index = m.attributes.getIndex(cf.constant_pool, name); - if (index != -1) { - attr = m.attributes.get(index); - assert attr instanceof RuntimeTypeAnnotations_attribute; - tAttr = (RuntimeTypeAnnotations_attribute)attr; - all += tAttr.annotations.length; - if (visible) - visibles += tAttr.annotations.length; - else - invisibles += tAttr.annotations.length; - } - // collect annotations from method's code attribute - index = m.attributes.getIndex(cf.constant_pool, Attribute.Code); - if(index!= -1) { - attr = m.attributes.get(index); - assert attr instanceof Code_attribute; - cAttr = (Code_attribute)attr; - index = cAttr.attributes.getIndex(cf.constant_pool, name); - if(index!= -1) { - attr = cAttr.attributes.get(index); - assert attr instanceof RuntimeTypeAnnotations_attribute; - tAttr = (RuntimeTypeAnnotations_attribute)attr; - all += tAttr.annotations.length; - if (visible) - visibles += tAttr.annotations.length; - else - invisibles += tAttr.annotations.length; - } + if (m instanceof MethodModel) { + attr_instance = m.findAttribute(Attributes.CODE).orElse(null); + if(attr_instance!= null) { + CodeAttribute cAttr = (CodeAttribute)attr_instance; + attr_instance = cAttr.findAttribute(attr_name).orElse(null); + if(attr_instance!= null) { + switch (attr_instance) { + case RuntimeVisibleTypeAnnotationsAttribute tAttr -> { + all += tAttr.annotations().size(); + visibles += tAttr.annotations().size(); + } + case RuntimeInvisibleTypeAnnotationsAttribute tAttr -> { + all += tAttr.annotations().size(); + invisibles += tAttr.annotations().size(); + } + default -> throw new AssertionError(); + } + } + } } } - // test the result of Attributes.getIndex according to expectations - // encoded in the method's name - void test(ClassFile cf, Field m, String name, boolean visible) { - int index = m.attributes.getIndex(cf.constant_pool, name); - if (index != -1) { - Attribute attr = m.attributes.get(index); - assert attr instanceof RuntimeTypeAnnotations_attribute; - RuntimeTypeAnnotations_attribute tAttr = (RuntimeTypeAnnotations_attribute)attr; - all += tAttr.annotations.length; - if (visible) - visibles += tAttr.annotations.length; - else - invisibles += tAttr.annotations.length; - } - } + File writeTestFile() throws IOException { File f = new File("TestPresence.java"); diff --git a/test/langtools/tools/javap/typeAnnotations/PresenceInner.java b/test/langtools/tools/javap/typeAnnotations/PresenceInner.java index c8d7c119c94..94f6ee15e0e 100644 --- a/test/langtools/tools/javap/typeAnnotations/PresenceInner.java +++ b/test/langtools/tools/javap/typeAnnotations/PresenceInner.java @@ -22,13 +22,18 @@ */ import java.io.*; -import com.sun.tools.classfile.*; +import jdk.internal.classfile.*; +import jdk.internal.classfile.attribute.*; /* * @test PresenceInner * @bug 6843077 * @summary test that annotations in inner types count only once - * @modules jdk.jdeps/com.sun.tools.classfile + * @modules java.base/jdk.internal.classfile + * java.base/jdk.internal.classfile.attribute + * java.base/jdk.internal.classfile.constantpool + * java.base/jdk.internal.classfile.instruction + * java.base/jdk.internal.classfile.components */ public class PresenceInner { @@ -40,13 +45,13 @@ public void run() throws Exception { File javaFile = writeTestFile(); File classFile = compileTestFile(javaFile); - ClassFile cf = ClassFile.read(classFile); - test(cf); - for (Field f : cf.fields) { - test(cf, f); + ClassModel cm = Classfile.of().parse(classFile.toPath()); + test(cm); + for (FieldModel fm : cm.fields()) { + test(fm); } - for (Method m: cf.methods) { - test(cf, m); + for (MethodModel mm: cm.methods()) { + test(mm); } // counts are zero when vising outer class @@ -54,13 +59,13 @@ public void run() throws Exception { // visit inner class File innerFile = new File("Test$1Inner.class"); - ClassFile icf = ClassFile.read(innerFile); - test(icf); - for (Field f : icf.fields) { - test(cf, f); + ClassModel icm = Classfile.of().parse(innerFile.toPath()); + test(icm); + for (FieldModel fm : icm.fields()) { + test(fm); } - for (Method m: icf.methods) { - test(cf, m); + for (MethodModel mm: icm.methods()) { + test(mm); } countAnnotations(1); @@ -69,66 +74,26 @@ public void run() throws Exception { System.out.println("PASSED"); } - void test(ClassFile cf) { - test(cf, Attribute.RuntimeVisibleTypeAnnotations, true); - test(cf, Attribute.RuntimeInvisibleTypeAnnotations, false); + void test(AttributedElement m) { + test(m, Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS); + test(m, Attributes.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS); } - void test(ClassFile cf, Method m) { - test(cf, m, Attribute.RuntimeVisibleTypeAnnotations, true); - test(cf, m, Attribute.RuntimeInvisibleTypeAnnotations, false); - } - - void test(ClassFile cf, Field m) { - test(cf, m, Attribute.RuntimeVisibleTypeAnnotations, true); - test(cf, m, Attribute.RuntimeInvisibleTypeAnnotations, false); - } - - // test the result of Attributes.getIndex according to expectations - // encoded in the method's name - void test(ClassFile cf, String name, boolean visible) { - int index = cf.attributes.getIndex(cf.constant_pool, name); - if (index != -1) { - Attribute attr = cf.attributes.get(index); - assert attr instanceof RuntimeTypeAnnotations_attribute; - RuntimeTypeAnnotations_attribute tAttr = (RuntimeTypeAnnotations_attribute)attr; - all += tAttr.annotations.length; - if (visible) - visibles += tAttr.annotations.length; - else - invisibles += tAttr.annotations.length; - } - } - - // test the result of Attributes.getIndex according to expectations - // encoded in the method's name - void test(ClassFile cf, Method m, String name, boolean visible) { - int index = m.attributes.getIndex(cf.constant_pool, name); - if (index != -1) { - Attribute attr = m.attributes.get(index); - assert attr instanceof RuntimeTypeAnnotations_attribute; - RuntimeTypeAnnotations_attribute tAttr = (RuntimeTypeAnnotations_attribute)attr; - all += tAttr.annotations.length; - if (visible) - visibles += tAttr.annotations.length; - else - invisibles += tAttr.annotations.length; - } - } - - // test the result of Attributes.getIndex according to expectations - // encoded in the method's name - void test(ClassFile cf, Field m, String name, boolean visible) { - int index = m.attributes.getIndex(cf.constant_pool, name); - if (index != -1) { - Attribute attr = m.attributes.get(index); - assert attr instanceof RuntimeTypeAnnotations_attribute; - RuntimeTypeAnnotations_attribute tAttr = (RuntimeTypeAnnotations_attribute)attr; - all += tAttr.annotations.length; - if (visible) - visibles += tAttr.annotations.length; - else - invisibles += tAttr.annotations.length; + // test the result of AttributedElement.findAttribute according to expectations + > void test(AttributedElement m, AttributeMapper attr_name) { + Attribute attr_instance = m.findAttribute(attr_name).orElse(null); + if (attr_instance != null) { + switch (attr_instance) { + case RuntimeVisibleTypeAnnotationsAttribute tAttr -> { + all += tAttr.annotations().size(); + visibles += tAttr.annotations().size(); + } + case RuntimeInvisibleTypeAnnotationsAttribute tAttr -> { + all += tAttr.annotations().size(); + invisibles += tAttr.annotations().size(); + } + default -> throw new AssertionError(); + } } } diff --git a/test/langtools/tools/javap/typeAnnotations/TypeCasts.java b/test/langtools/tools/javap/typeAnnotations/TypeCasts.java index af56cc78257..0382301cae2 100644 --- a/test/langtools/tools/javap/typeAnnotations/TypeCasts.java +++ b/test/langtools/tools/javap/typeAnnotations/TypeCasts.java @@ -21,15 +21,20 @@ * questions. */ +import jdk.internal.classfile.*; +import jdk.internal.classfile.attribute.*; import java.io.*; -import com.sun.tools.classfile.*; /* * @test * @bug 6843077 * @summary test that typecasts annotation are emitted if only the cast * expression is optimized away - * @modules jdk.jdeps/com.sun.tools.classfile + * @modules java.base/jdk.internal.classfile + * java.base/jdk.internal.classfile.attribute + * java.base/jdk.internal.classfile.constantpool + * java.base/jdk.internal.classfile.instruction + * java.base/jdk.internal.classfile.components */ public class TypeCasts { @@ -41,9 +46,9 @@ public void run() throws Exception { File javaFile = writeTestFile(); File classFile = compileTestFile(javaFile); - ClassFile cf = ClassFile.read(classFile); - for (Method m: cf.methods) { - test(cf, m); + ClassModel cm = Classfile.of().parse(classFile.toPath()); + for (MethodModel mm: cm.methods()) { + test(mm); } countAnnotations(); @@ -53,34 +58,34 @@ public void run() throws Exception { System.out.println("PASSED"); } - void test(ClassFile cf, Method m) { - test(cf, m, Attribute.RuntimeVisibleTypeAnnotations, true); - test(cf, m, Attribute.RuntimeInvisibleTypeAnnotations, false); + void test(MethodModel mm) { + test(mm, Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS); + test(mm, Attributes.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS); } - // test the result of Attributes.getIndex according to expectations + // test the result of MethodModel.findAttribute according to expectations // encoded in the method's name - void test(ClassFile cf, Method m, String name, boolean visible) { - Attribute attr = null; - Code_attribute cAttr = null; - - int index = m.attributes.getIndex(cf.constant_pool, Attribute.Code); - if(index!= -1) { - attr = m.attributes.get(index); - assert attr instanceof Code_attribute; - cAttr = (Code_attribute)attr; - index = cAttr.attributes.getIndex(cf.constant_pool, name); - if(index!= -1) { - attr = cAttr.attributes.get(index); - assert attr instanceof RuntimeTypeAnnotations_attribute; - RuntimeTypeAnnotations_attribute tAttr = (RuntimeTypeAnnotations_attribute)attr; - all += tAttr.annotations.length; - if (visible) - visibles += tAttr.annotations.length; - else - invisibles += tAttr.annotations.length; - } + > void test(MethodModel mm, AttributeMapper attr_name) { + Attribute attr; + CodeAttribute cAttr; + + cAttr = mm.findAttribute(Attributes.CODE).orElse(null); + if (cAttr != null) { + attr = cAttr.findAttribute(attr_name).orElse(null); + if (attr != null) { + switch (attr) { + case RuntimeVisibleTypeAnnotationsAttribute tAttr -> { + all += tAttr.annotations().size(); + visibles += tAttr.annotations().size(); + } + case RuntimeInvisibleTypeAnnotationsAttribute tAttr -> { + all += tAttr.annotations().size(); + invisibles += tAttr.annotations().size(); + } + default -> throw new AssertionError(); + } + } } } diff --git a/test/langtools/tools/javap/typeAnnotations/Visibility.java b/test/langtools/tools/javap/typeAnnotations/Visibility.java index 0e9a73af7da..a332ecc2282 100644 --- a/test/langtools/tools/javap/typeAnnotations/Visibility.java +++ b/test/langtools/tools/javap/typeAnnotations/Visibility.java @@ -22,13 +22,19 @@ */ import java.io.*; -import com.sun.tools.classfile.*; +import jdk.internal.classfile.*; +import jdk.internal.classfile.Attributes; +import jdk.internal.classfile.attribute.*; /* * @test Visibility * @bug 6843077 * @summary test that type annotations are recorded in the classfile - * @modules jdk.jdeps/com.sun.tools.classfile + * @modules java.base/jdk.internal.classfile + * java.base/jdk.internal.classfile.attribute + * java.base/jdk.internal.classfile.constantpool + * java.base/jdk.internal.classfile.instruction + * java.base/jdk.internal.classfile.components */ public class Visibility { @@ -40,9 +46,9 @@ public void run() throws Exception { File javaFile = writeTestFile(); File classFile = compileTestFile(javaFile); - ClassFile cf = ClassFile.read(classFile); - for (Method m: cf.methods) { - test(cf, m); + ClassModel cm = Classfile.of().parse(classFile.toPath()); + for (MethodModel mm: cm.methods()) { + test(mm); } countAnnotations(); @@ -52,24 +58,27 @@ public void run() throws Exception { System.out.println("PASSED"); } - void test(ClassFile cf, Method m) { - test(cf, m, Attribute.RuntimeVisibleTypeAnnotations, true); - test(cf, m, Attribute.RuntimeInvisibleTypeAnnotations, false); + void test(MethodModel mm) { + test(mm, Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS); + test(mm, Attributes.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS); } - // test the result of Attributes.getIndex according to expectations + // test the result of mm.findAttribute according to expectations // encoded in the method's name - void test(ClassFile cf, Method m, String name, boolean visible) { - int index = m.attributes.getIndex(cf.constant_pool, name); - if (index != -1) { - Attribute attr = m.attributes.get(index); - assert attr instanceof RuntimeTypeAnnotations_attribute; - RuntimeTypeAnnotations_attribute tAttr = (RuntimeTypeAnnotations_attribute)attr; - all += tAttr.annotations.length; - if (visible) - visibles += tAttr.annotations.length; - else - invisibles += tAttr.annotations.length; + > void test(MethodModel mm, AttributeMapper attr_name) { + Attribute attr_instance = mm.findAttribute(attr_name).orElse(null); + if (attr_instance != null) { + switch (attr_instance) { + case RuntimeInvisibleTypeAnnotationsAttribute tAttr -> { + all += tAttr.annotations().size(); + invisibles += tAttr.annotations().size(); + } + case RuntimeVisibleTypeAnnotationsAttribute tAttr -> { + all += tAttr.annotations().size(); + visibles += tAttr.annotations().size(); + } + default -> throw new AssertionError(); + } } } @@ -109,7 +118,7 @@ File writeTestFile() throws IOException { } File compileTestFile(File f) { - int rc = com.sun.tools.javac.Main.compile(new String[] {"-g", f.getPath() }); + int rc = com.sun.tools.javac.Main.compile(new String[] {"-g", f.getPath() }); if (rc != 0) throw new Error("compilation failed. rc=" + rc); String path = f.getPath(); diff --git a/test/langtools/tools/javap/typeAnnotations/Wildcards.java b/test/langtools/tools/javap/typeAnnotations/Wildcards.java index 3b10d606ee6..bc2cd3d4423 100644 --- a/test/langtools/tools/javap/typeAnnotations/Wildcards.java +++ b/test/langtools/tools/javap/typeAnnotations/Wildcards.java @@ -22,13 +22,18 @@ */ import java.io.*; -import com.sun.tools.classfile.*; +import jdk.internal.classfile.*; +import jdk.internal.classfile.attribute.*; /* * @test Wildcards * @bug 6843077 * @summary test that annotations target wildcards get emitted to classfile - * @modules jdk.jdeps/com.sun.tools.classfile + * @modules java.base/jdk.internal.classfile + * java.base/jdk.internal.classfile.attribute + * java.base/jdk.internal.classfile.constantpool + * java.base/jdk.internal.classfile.instruction + * java.base/jdk.internal.classfile.components */ public class Wildcards { public static void main(String[] args) throws Exception { @@ -39,13 +44,13 @@ public void run() throws Exception { File javaFile = writeTestFile(); File classFile = compileTestFile(javaFile); - ClassFile cf = ClassFile.read(classFile); - test(cf); - for (Field f : cf.fields) { - test(cf, f); + ClassModel cm = Classfile.of().parse(classFile.toPath()); + test(cm); + for (FieldModel fm : cm.fields()) { + test(fm); } - for (Method m: cf.methods) { - test(cf, m); + for (MethodModel mm: cm.methods()) { + test(mm); } countAnnotations(); @@ -54,72 +59,28 @@ public void run() throws Exception { throw new Exception(errors + " errors found"); System.out.println("PASSED"); } - - void test(ClassFile cf) { - test(cf, Attribute.RuntimeVisibleTypeAnnotations, true); - test(cf, Attribute.RuntimeInvisibleTypeAnnotations, false); - } - - void test(ClassFile cf, Method m) { - test(cf, m, Attribute.RuntimeVisibleTypeAnnotations, true); - test(cf, m, Attribute.RuntimeInvisibleTypeAnnotations, false); + void test(AttributedElement m) { + test(m, Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS); + test(m, Attributes.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS); } - - void test(ClassFile cf, Field m) { - test(cf, m, Attribute.RuntimeVisibleTypeAnnotations, true); - test(cf, m, Attribute.RuntimeInvisibleTypeAnnotations, false); - } - - // test the result of Attributes.getIndex according to expectations - // encoded in the method's name - void test(ClassFile cf, String name, boolean visible) { - int index = cf.attributes.getIndex(cf.constant_pool, name); - if (index != -1) { - Attribute attr = cf.attributes.get(index); - assert attr instanceof RuntimeTypeAnnotations_attribute; - RuntimeTypeAnnotations_attribute tAttr = (RuntimeTypeAnnotations_attribute)attr; - all += tAttr.annotations.length; - if (visible) - visibles += tAttr.annotations.length; - else - invisibles += tAttr.annotations.length; + > void test(AttributedElement m, AttributeMapper attr_name) { + Attribute attr_instance = m.findAttribute(attr_name).orElse(null); + if (attr_instance != null) { + switch (attr_instance) { + case RuntimeVisibleTypeAnnotationsAttribute tAttr -> { + all += tAttr.annotations().size(); + visibles += tAttr.annotations().size(); + } + case RuntimeInvisibleTypeAnnotationsAttribute tAttr -> { + all += tAttr.annotations().size(); + invisibles += tAttr.annotations().size(); + } + default -> throw new AssertionError(); + } } } - - // test the result of Attributes.getIndex according to expectations - // encoded in the method's name - void test(ClassFile cf, Method m, String name, boolean visible) { - int index = m.attributes.getIndex(cf.constant_pool, name); - if (index != -1) { - Attribute attr = m.attributes.get(index); - assert attr instanceof RuntimeTypeAnnotations_attribute; - RuntimeTypeAnnotations_attribute tAttr = (RuntimeTypeAnnotations_attribute)attr; - all += tAttr.annotations.length; - if (visible) - visibles += tAttr.annotations.length; - else - invisibles += tAttr.annotations.length; - } - } - - // test the result of Attributes.getIndex according to expectations - // encoded in the method's name - void test(ClassFile cf, Field m, String name, boolean visible) { - int index = m.attributes.getIndex(cf.constant_pool, name); - if (index != -1) { - Attribute attr = m.attributes.get(index); - assert attr instanceof RuntimeTypeAnnotations_attribute; - RuntimeTypeAnnotations_attribute tAttr = (RuntimeTypeAnnotations_attribute)attr; - all += tAttr.annotations.length; - if (visible) - visibles += tAttr.annotations.length; - else - invisibles += tAttr.annotations.length; - } - } - File writeTestFile() throws IOException { - File f = new File("Test.java"); + File f = new File("Test.java"); PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(f))); out.println("import java.lang.annotation.*;"); out.println("import java.util.*;"); From 78f67993f89792d2f0d8dcf04ba12ee93b336a13 Mon Sep 17 00:00:00 2001 From: Gerard Ziemski Date: Mon, 31 Jul 2023 15:12:22 +0000 Subject: [PATCH 05/11] 8293972: runtime/NMT/NMTInitializationTest.java#default_long-off failed with "Suspiciously long bucket chains in lookup table." Reviewed-by: stuefe, dholmes --- src/hotspot/share/services/nmtPreInit.hpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/hotspot/share/services/nmtPreInit.hpp b/src/hotspot/share/services/nmtPreInit.hpp index f104b0a2600..c6c504e99cd 100644 --- a/src/hotspot/share/services/nmtPreInit.hpp +++ b/src/hotspot/share/services/nmtPreInit.hpp @@ -143,22 +143,25 @@ class NMTPreInitAllocationTable { // VMs with insanely long command lines maybe ~700-1000. Which gives us an expected // load factor of ~.1. Hash collisions should be very rare. // ~8000 entries cost us ~64K for this table (64-bit), which is acceptable. - static const int table_size = 7919; + // We chose 8191, as this is a Mersenne prime (2^x - 1), which for a random + // polynomial modulo p = (2^x - 1) is uniformily distributed in [p], so each + // bit has the same distribution. + static const int table_size = 8191; // i.e. 8191==(2^13 - 1); NMTPreInitAllocation* _entries[table_size]; typedef int index_t; const index_t invalid_index = -1; - static unsigned calculate_hash(const void* p) { - uintptr_t tmp = p2i(p); - unsigned hash = (unsigned)tmp - LP64_ONLY( ^ (unsigned)(tmp >> 32)); - return hash; + static uint64_t calculate_hash(const void* p) { + // Keep hash function simple, the modulo + // operation in index function will do the "heavy lifting". + return (uint64_t)(p); } static index_t index_for_key(const void* p) { - const unsigned hash = calculate_hash(p); + const uint64_t hash = calculate_hash(p); + // "table_size" is a Mersenne prime, so "modulo" is all we need here. return hash % table_size; } From e47a84f23dd2608c6f5748093eefe301fb5bf750 Mon Sep 17 00:00:00 2001 From: Hai-May Chao Date: Mon, 31 Jul 2023 15:18:04 +0000 Subject: [PATCH 06/11] 8312489: Increase jdk.jar.maxSignatureFileSize default which is too low for JARs such as WhiteSource/Mend unified agent jar Reviewed-by: mullan, mbaesken --- .../share/classes/java/util/jar/JarFile.java | 4 +++- .../sun/security/util/SignatureFileVerifier.java | 12 ++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/java.base/share/classes/java/util/jar/JarFile.java b/src/java.base/share/classes/java/util/jar/JarFile.java index c8fcac4bda0..ca8c726129e 100644 --- a/src/java.base/share/classes/java/util/jar/JarFile.java +++ b/src/java.base/share/classes/java/util/jar/JarFile.java @@ -802,7 +802,9 @@ private byte[] getBytes(ZipEntry ze) throws IOException { throw new IOException("Unsupported size: " + uncompressedSize + " for JarEntry " + ze.getName() + ". Allowed max size: " + - SignatureFileVerifier.MAX_SIG_FILE_SIZE + " bytes"); + SignatureFileVerifier.MAX_SIG_FILE_SIZE + " bytes. " + + "You can use the jdk.jar.maxSignatureFileSize " + + "system property to increase the default value."); } int len = (int)uncompressedSize; int bytesRead; diff --git a/src/java.base/share/classes/sun/security/util/SignatureFileVerifier.java b/src/java.base/share/classes/sun/security/util/SignatureFileVerifier.java index b1da2186660..e16ae803b96 100644 --- a/src/java.base/share/classes/sun/security/util/SignatureFileVerifier.java +++ b/src/java.base/share/classes/sun/security/util/SignatureFileVerifier.java @@ -847,16 +847,16 @@ private static int initializeMaxSigFileSize() { * the maximum allowed number of bytes for the signature-related files * in a JAR file. */ - Integer tmp = GetIntegerAction.privilegedGetProperty( - "jdk.jar.maxSignatureFileSize", 8000000); + int tmp = GetIntegerAction.privilegedGetProperty( + "jdk.jar.maxSignatureFileSize", 16000000); if (tmp < 0 || tmp > MAX_ARRAY_SIZE) { if (debug != null) { - debug.println("Default signature file size 8000000 bytes " + - "is used as the specified size for the " + - "jdk.jar.maxSignatureFileSize system property " + + debug.println("The default signature file size of 16000000 bytes " + + "will be used for the jdk.jar.maxSignatureFileSize " + + "system property since the specified value " + "is out of range: " + tmp); } - tmp = 8000000; + tmp = 16000000; } return tmp; } From 5362ec9c6e9123d00288497ac9d1879a2bb1ca64 Mon Sep 17 00:00:00 2001 From: Thomas Stuefe Date: Mon, 31 Jul 2023 16:51:29 +0000 Subject: [PATCH 07/11] 8312492: Remove THP sanity checks at VM startup Reviewed-by: dholmes, coleenp --- src/hotspot/os/linux/os_linux.cpp | 31 ++----------------- src/hotspot/os/linux/os_linux.hpp | 1 - .../LargePages/TestLargePagesFlags.java | 7 +++++ 3 files changed, 10 insertions(+), 29 deletions(-) diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index 9037e54fe61..5e5aac601e9 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -3563,27 +3563,6 @@ bool os::unguard_memory(char* addr, size_t size) { return linux_mprotect(addr, size, PROT_READ|PROT_WRITE); } -bool os::Linux::transparent_huge_pages_sanity_check(bool warn, - size_t page_size) { - bool result = false; - void *p = mmap(nullptr, page_size * 2, PROT_READ|PROT_WRITE, - MAP_ANONYMOUS|MAP_PRIVATE, - -1, 0); - if (p != MAP_FAILED) { - void *aligned_p = align_up(p, page_size); - - result = madvise(aligned_p, page_size, MADV_HUGEPAGE) == 0; - - munmap(p, page_size * 2); - } - - if (warn && !result) { - warning("TransparentHugePages is not supported by the operating system."); - } - - return result; -} - int os::Linux::hugetlbfs_page_size_flag(size_t page_size) { if (page_size != HugePages::default_static_hugepage_size()) { return (exact_log2(page_size) << MAP_HUGE_SHIFT); @@ -3715,13 +3694,9 @@ bool os::Linux::setup_large_page_type(size_t page_size) { } if (UseTransparentHugePages) { - bool warn_on_failure = !FLAG_IS_DEFAULT(UseTransparentHugePages); - if (transparent_huge_pages_sanity_check(warn_on_failure, page_size)) { - UseHugeTLBFS = false; - UseSHM = false; - return true; - } - UseTransparentHugePages = false; + UseHugeTLBFS = false; + UseSHM = false; + return true; } if (UseHugeTLBFS) { diff --git a/src/hotspot/os/linux/os_linux.hpp b/src/hotspot/os/linux/os_linux.hpp index ace7e4ab2dd..6dd33b94efa 100644 --- a/src/hotspot/os/linux/os_linux.hpp +++ b/src/hotspot/os/linux/os_linux.hpp @@ -76,7 +76,6 @@ class os::Linux { static GrowableArray* nindex_to_node() { return _nindex_to_node; } static bool setup_large_page_type(size_t page_size); - static bool transparent_huge_pages_sanity_check(bool warn, size_t pages_size); static bool hugetlbfs_sanity_check(bool warn, size_t page_size); static bool shm_hugetlbfs_sanity_check(bool warn, size_t page_size); diff --git a/test/hotspot/jtreg/runtime/memory/LargePages/TestLargePagesFlags.java b/test/hotspot/jtreg/runtime/memory/LargePages/TestLargePagesFlags.java index d0d9b4d2213..3679ecce1f0 100644 --- a/test/hotspot/jtreg/runtime/memory/LargePages/TestLargePagesFlags.java +++ b/test/hotspot/jtreg/runtime/memory/LargePages/TestLargePagesFlags.java @@ -37,6 +37,7 @@ import jdk.test.lib.process.ProcessTools; import java.util.ArrayList; +import java.util.Arrays; public class TestLargePagesFlags { @@ -299,6 +300,9 @@ public void expect(Flag... expectedFlags) throws Exception { throw new IllegalStateException("Must run use() before expect()"); } + System.out.println("Using: " + Arrays.toString(useFlags)); + System.out.println("Expecting: " + Arrays.toString(expectedFlags)); + OutputAnalyzer output = executeNewJVM(useFlags); for (Flag flag : expectedFlags) { @@ -381,6 +385,9 @@ public String name() { public String value() { return Boolean.toString(value); } + + @Override + public String toString() { return flagString(); } } private static interface Flag { From 86783b985175de3a0c02215a862b2a2749d8b408 Mon Sep 17 00:00:00 2001 From: Matias Saavedra Silva Date: Mon, 31 Jul 2023 18:41:38 +0000 Subject: [PATCH 08/11] 8301996: Move field resolution information out of the cpCache Co-authored-by: Gui Cao Co-authored-by: Dingli Zhang Co-authored-by: Martin Doerr Reviewed-by: coleenp, fparain --- .../cpu/aarch64/interp_masm_aarch64.cpp | 19 +- .../cpu/aarch64/interp_masm_aarch64.hpp | 1 + .../cpu/aarch64/templateTable_aarch64.cpp | 240 +++++++++------ src/hotspot/cpu/ppc/interp_masm_ppc.hpp | 1 + src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp | 20 +- src/hotspot/cpu/ppc/templateTable_ppc_64.cpp | 149 ++++++--- src/hotspot/cpu/riscv/interp_masm_riscv.cpp | 20 +- src/hotspot/cpu/riscv/interp_masm_riscv.hpp | 1 + src/hotspot/cpu/riscv/templateTable_riscv.cpp | 224 ++++++++------ src/hotspot/cpu/x86/interp_masm_x86.cpp | 18 +- src/hotspot/cpu/x86/interp_masm_x86.hpp | 2 +- src/hotspot/cpu/x86/templateTable_x86.cpp | 287 ++++++++++-------- src/hotspot/cpu/zero/zeroInterpreter_zero.cpp | 20 +- src/hotspot/share/ci/ciStreams.cpp | 4 +- src/hotspot/share/interpreter/bytecode.cpp | 4 +- .../share/interpreter/bytecodeTracer.cpp | 5 +- .../share/interpreter/bytecodeUtils.cpp | 14 +- src/hotspot/share/interpreter/bytecodes.hpp | 1 + .../share/interpreter/interpreterRuntime.cpp | 45 ++- .../share/interpreter/interpreterRuntime.hpp | 6 +- src/hotspot/share/interpreter/rewriter.cpp | 31 +- src/hotspot/share/interpreter/rewriter.hpp | 4 + .../share/interpreter/templateTable.hpp | 9 + .../interpreter/zero/bytecodeInterpreter.cpp | 124 ++++---- src/hotspot/share/oops/constantPool.cpp | 4 +- src/hotspot/share/oops/constantPool.hpp | 4 + .../share/oops/constantPool.inline.hpp | 9 + src/hotspot/share/oops/cpCache.cpp | 73 +++-- src/hotspot/share/oops/cpCache.hpp | 18 +- src/hotspot/share/oops/cpCache.inline.hpp | 15 +- src/hotspot/share/oops/generateOopMap.cpp | 16 +- src/hotspot/share/oops/resolvedFieldEntry.cpp | 50 +++ src/hotspot/share/oops/resolvedFieldEntry.hpp | 144 +++++++++ .../prims/jvmtiClassFileReconstituter.cpp | 8 +- src/hotspot/share/prims/methodComparator.cpp | 13 +- src/hotspot/share/prims/whitebox.cpp | 20 ++ src/hotspot/share/runtime/vmStructs.cpp | 24 +- .../sun/jvm/hotspot/oops/ConstantPool.java | 3 +- .../jvm/hotspot/oops/ConstantPoolCache.java | 8 + .../jvm/hotspot/oops/ResolvedFieldArray.java | 73 +++++ .../jvm/hotspot/oops/ResolvedFieldEntry.java | 64 ++++ .../gtest/oops/test_cpCache_output.cpp | 12 +- .../compilerToVM/ConstantPoolTestsHelper.java | 7 + .../interpreter/BytecodeTracerTest.java | 3 +- test/lib/jdk/test/whitebox/WhiteBox.java | 12 + 45 files changed, 1283 insertions(+), 546 deletions(-) create mode 100644 src/hotspot/share/oops/resolvedFieldEntry.cpp create mode 100644 src/hotspot/share/oops/resolvedFieldEntry.hpp create mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ResolvedFieldArray.java create mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ResolvedFieldEntry.java diff --git a/src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp b/src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp index 3f0646c5a0b..a86cc40ab50 100644 --- a/src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp @@ -36,6 +36,7 @@ #include "oops/markWord.hpp" #include "oops/method.hpp" #include "oops/methodData.hpp" +#include "oops/resolvedFieldEntry.hpp" #include "oops/resolvedIndyEntry.hpp" #include "prims/jvmtiExport.hpp" #include "prims/jvmtiThreadState.hpp" @@ -1881,8 +1882,24 @@ void InterpreterMacroAssembler::load_resolved_indy_entry(Register cache, Registe get_cache_index_at_bcp(index, 1, sizeof(u4)); // Get address of invokedynamic array ldr(cache, Address(rcpool, in_bytes(ConstantPoolCache::invokedynamic_entries_offset()))); - // Scale the index to be the entry index * sizeof(ResolvedInvokeDynamicInfo) + // Scale the index to be the entry index * sizeof(ResolvedIndyEntry) lsl(index, index, log2i_exact(sizeof(ResolvedIndyEntry))); add(cache, cache, Array::base_offset_in_bytes()); lea(cache, Address(cache, index)); } + +void InterpreterMacroAssembler::load_field_entry(Register cache, Register index, int bcp_offset) { + // Get index out of bytecode pointer + get_cache_index_at_bcp(index, bcp_offset, sizeof(u2)); + // Take shortcut if the size is a power of 2 + if (is_power_of_2(sizeof(ResolvedFieldEntry))) { + lsl(index, index, log2i_exact(sizeof(ResolvedFieldEntry))); // Scale index by power of 2 + } else { + mov(cache, sizeof(ResolvedFieldEntry)); + mul(index, index, cache); // Scale the index to be the entry index * sizeof(ResolvedFieldEntry) + } + // Get address of field entries array + ldr(cache, Address(rcpool, ConstantPoolCache::field_entries_offset())); + add(cache, cache, Array::base_offset_in_bytes()); + lea(cache, Address(cache, index)); +} diff --git a/src/hotspot/cpu/aarch64/interp_masm_aarch64.hpp b/src/hotspot/cpu/aarch64/interp_masm_aarch64.hpp index 019eb235581..70822b6c424 100644 --- a/src/hotspot/cpu/aarch64/interp_masm_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/interp_masm_aarch64.hpp @@ -321,6 +321,7 @@ class InterpreterMacroAssembler: public MacroAssembler { } void load_resolved_indy_entry(Register cache, Register index); + void load_field_entry(Register cache, Register index, int bcp_offset = 1); }; #endif // CPU_AARCH64_INTERP_MASM_AARCH64_HPP diff --git a/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp b/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp index a0073bcc512..5d57505ddc5 100644 --- a/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp @@ -38,6 +38,7 @@ #include "oops/method.hpp" #include "oops/objArrayKlass.hpp" #include "oops/oop.inline.hpp" +#include "oops/resolvedFieldEntry.hpp" #include "oops/resolvedIndyEntry.hpp" #include "prims/jvmtiExport.hpp" #include "prims/methodHandles.hpp" @@ -187,7 +188,14 @@ void TemplateTable::patch_bytecode(Bytecodes::Code bc, Register bc_reg, // additional, required work. assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range"); assert(load_bc_into_bc_reg, "we use bc_reg as temp"); - __ get_cache_and_index_and_bytecode_at_bcp(temp_reg, bc_reg, temp_reg, byte_no, 1); + __ load_field_entry(temp_reg, bc_reg); + if (byte_no == f1_byte) { + __ lea(temp_reg, Address(temp_reg, in_bytes(ResolvedFieldEntry::get_code_offset()))); + } else { + __ lea(temp_reg, Address(temp_reg, in_bytes(ResolvedFieldEntry::put_code_offset()))); + } + // Load-acquire the bytecode to match store-release in ResolvedFieldEntry::fill_in() + __ ldarb(temp_reg, temp_reg); __ movw(bc_reg, bc); __ cbzw(temp_reg, L_patch_done); // don't patch } @@ -2247,11 +2255,6 @@ void TemplateTable::resolve_cache_and_index(int byte_no, Label resolved, clinit_barrier_slow; Bytecodes::Code code = bytecode(); - switch (code) { - case Bytecodes::_nofast_getfield: code = Bytecodes::_getfield; break; - case Bytecodes::_nofast_putfield: code = Bytecodes::_putfield; break; - default: break; - } assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range"); __ get_cache_and_index_and_bytecode_at_bcp(Rcache, index, temp, byte_no, 1, index_size); @@ -2279,6 +2282,69 @@ void TemplateTable::resolve_cache_and_index(int byte_no, } } +void TemplateTable::resolve_cache_and_index_for_field(int byte_no, + Register Rcache, + Register index) { + const Register temp = r19; + assert_different_registers(Rcache, index, temp); + + Label resolved; + + Bytecodes::Code code = bytecode(); + switch (code) { + case Bytecodes::_nofast_getfield: code = Bytecodes::_getfield; break; + case Bytecodes::_nofast_putfield: code = Bytecodes::_putfield; break; + default: break; + } + + assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range"); + __ load_field_entry(Rcache, index); + if (byte_no == f1_byte) { + __ lea(temp, Address(Rcache, in_bytes(ResolvedFieldEntry::get_code_offset()))); + } else { + __ lea(temp, Address(Rcache, in_bytes(ResolvedFieldEntry::put_code_offset()))); + } + // Load-acquire the bytecode to match store-release in ResolvedFieldEntry::fill_in() + __ ldarb(temp, temp); + __ subs(zr, temp, (int) code); // have we resolved this bytecode? + __ br(Assembler::EQ, resolved); + + // resolve first time through + address entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_from_cache); + __ mov(temp, (int) code); + __ call_VM(noreg, entry, temp); + + // Update registers with resolved info + __ load_field_entry(Rcache, index); + __ bind(resolved); +} + +void TemplateTable::load_resolved_field_entry(Register obj, + Register cache, + Register tos_state, + Register offset, + Register flags, + bool is_static = false) { + assert_different_registers(cache, tos_state, flags, offset); + + // Field offset + __ load_sized_value(offset, Address(cache, in_bytes(ResolvedFieldEntry::field_offset_offset())), sizeof(int), true /*is_signed*/); + + // Flags + __ load_unsigned_byte(flags, Address(cache, in_bytes(ResolvedFieldEntry::flags_offset()))); + + // TOS state + __ load_unsigned_byte(tos_state, Address(cache, in_bytes(ResolvedFieldEntry::type_offset()))); + + // Klass overwrite register + if (is_static) { + __ ldr(obj, Address(cache, ResolvedFieldEntry::field_holder_offset())); + const int mirror_offset = in_bytes(Klass::java_mirror_offset()); + __ ldr(obj, Address(obj, mirror_offset)); + __ resolve_oop_handle(obj, r5, rscratch2); + } +} + // The Rcache and index registers must be set before call // n.b unlike x86 cache already includes the index offset void TemplateTable::load_field_cp_cache_entry(Register obj, @@ -2430,8 +2496,7 @@ void TemplateTable::jvmti_post_field_access(Register cache, Register index, __ ldrw(r0, Address(rscratch1)); __ cbzw(r0, L1); - __ get_cache_and_index_at_bcp(c_rarg2, c_rarg3, 1); - __ lea(c_rarg2, Address(c_rarg2, in_bytes(ConstantPoolCache::base_offset()))); + __ load_field_entry(c_rarg2, index); if (is_static) { __ mov(c_rarg1, zr); // null object reference @@ -2441,11 +2506,10 @@ void TemplateTable::jvmti_post_field_access(Register cache, Register index, } // c_rarg1: object pointer or null // c_rarg2: cache entry pointer - // c_rarg3: jvalue object on the stack __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::post_field_access), - c_rarg1, c_rarg2, c_rarg3); - __ get_cache_and_index_at_bcp(cache, index, 1); + c_rarg1, c_rarg2); + __ load_field_entry(cache, index); __ bind(L1); } } @@ -2459,17 +2523,17 @@ void TemplateTable::pop_and_check_object(Register r) void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteControl rc) { - const Register cache = r2; - const Register index = r3; - const Register obj = r4; - const Register off = r19; - const Register flags = r0; - const Register raw_flags = r6; - const Register bc = r4; // uses same reg as obj, so don't mix them + const Register cache = r4; + const Register obj = r4; + const Register index = r3; + const Register tos_state = r3; + const Register off = r19; + const Register flags = r6; + const Register bc = r4; // uses same reg as obj, so don't mix them - resolve_cache_and_index(byte_no, cache, index, sizeof(u2)); + resolve_cache_and_index_for_field(byte_no, cache, index); jvmti_post_field_access(cache, index, is_static, false); - load_field_cp_cache_entry(obj, cache, index, off, raw_flags, is_static); + load_resolved_field_entry(obj, cache, tos_state, off, flags, is_static); if (!is_static) { // obj is on the stack @@ -2484,7 +2548,7 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteContr // the stores in one method and we interpret the loads in another. if (!CompilerConfig::is_c1_or_interpreter_only_no_jvmci()){ Label notVolatile; - __ tbz(raw_flags, ConstantPoolCacheEntry::is_volatile_shift, notVolatile); + __ tbz(flags, ResolvedFieldEntry::is_volatile_shift, notVolatile); __ membar(MacroAssembler::AnyAny); __ bind(notVolatile); } @@ -2494,13 +2558,8 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteContr Label Done, notByte, notBool, notInt, notShort, notChar, notLong, notFloat, notObj, notDouble; - // x86 uses a shift and mask or wings it with a shift plus assert - // the mask is not needed. aarch64 just uses bitfield extract - __ ubfxw(flags, raw_flags, ConstantPoolCacheEntry::tos_state_shift, - ConstantPoolCacheEntry::tos_state_bits); - assert(btos == 0, "change code, btos != 0"); - __ cbnz(flags, notByte); + __ cbnz(tos_state, notByte); // Don't rewrite getstatic, only getfield if (is_static) rc = may_not_rewrite; @@ -2515,7 +2574,7 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteContr __ b(Done); __ bind(notByte); - __ cmp(flags, (u1)ztos); + __ cmp(tos_state, (u1)ztos); __ br(Assembler::NE, notBool); // ztos (same code as btos) @@ -2529,7 +2588,7 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteContr __ b(Done); __ bind(notBool); - __ cmp(flags, (u1)atos); + __ cmp(tos_state, (u1)atos); __ br(Assembler::NE, notObj); // atos do_oop_load(_masm, field, r0, IN_HEAP); @@ -2540,7 +2599,7 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteContr __ b(Done); __ bind(notObj); - __ cmp(flags, (u1)itos); + __ cmp(tos_state, (u1)itos); __ br(Assembler::NE, notInt); // itos __ access_load_at(T_INT, IN_HEAP, r0, field, noreg, noreg); @@ -2552,7 +2611,7 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteContr __ b(Done); __ bind(notInt); - __ cmp(flags, (u1)ctos); + __ cmp(tos_state, (u1)ctos); __ br(Assembler::NE, notChar); // ctos __ access_load_at(T_CHAR, IN_HEAP, r0, field, noreg, noreg); @@ -2564,7 +2623,7 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteContr __ b(Done); __ bind(notChar); - __ cmp(flags, (u1)stos); + __ cmp(tos_state, (u1)stos); __ br(Assembler::NE, notShort); // stos __ access_load_at(T_SHORT, IN_HEAP, r0, field, noreg, noreg); @@ -2576,7 +2635,7 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteContr __ b(Done); __ bind(notShort); - __ cmp(flags, (u1)ltos); + __ cmp(tos_state, (u1)ltos); __ br(Assembler::NE, notLong); // ltos __ access_load_at(T_LONG, IN_HEAP, r0, field, noreg, noreg); @@ -2588,7 +2647,7 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteContr __ b(Done); __ bind(notLong); - __ cmp(flags, (u1)ftos); + __ cmp(tos_state, (u1)ftos); __ br(Assembler::NE, notFloat); // ftos __ access_load_at(T_FLOAT, IN_HEAP, noreg /* ftos */, field, noreg, noreg); @@ -2601,7 +2660,7 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteContr __ bind(notFloat); #ifdef ASSERT - __ cmp(flags, (u1)dtos); + __ cmp(tos_state, (u1)dtos); __ br(Assembler::NE, notDouble); #endif // dtos @@ -2621,7 +2680,7 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteContr __ bind(Done); Label notVolatile; - __ tbz(raw_flags, ConstantPoolCacheEntry::is_volatile_shift, notVolatile); + __ tbz(flags, ResolvedFieldEntry::is_volatile_shift, notVolatile); __ membar(MacroAssembler::LoadLoad | MacroAssembler::LoadStore); __ bind(notVolatile); } @@ -2646,8 +2705,6 @@ void TemplateTable::getstatic(int byte_no) void TemplateTable::jvmti_post_field_mod(Register cache, Register index, bool is_static) { transition(vtos, vtos); - ByteSize cp_base_offset = ConstantPoolCache::base_offset(); - if (JvmtiExport::can_post_field_modification()) { // Check to see if a field modification watch has been set before // we take the time to call into the VM. @@ -2657,7 +2714,7 @@ void TemplateTable::jvmti_post_field_mod(Register cache, Register index, bool is __ ldrw(r0, Address(rscratch1)); __ cbz(r0, L1); - __ get_cache_and_index_at_bcp(c_rarg2, rscratch1, 1); + __ mov(c_rarg2, cache); if (is_static) { // Life is simple. Null out the object pointer. @@ -2667,12 +2724,7 @@ void TemplateTable::jvmti_post_field_mod(Register cache, Register index, bool is // the object. We don't know the size of the value, though; it // could be one or two words depending on its type. As a result, // we must find the type to determine where the object is. - __ ldrw(c_rarg3, Address(c_rarg2, - in_bytes(cp_base_offset + - ConstantPoolCacheEntry::flags_offset()))); - __ lsr(c_rarg3, c_rarg3, - ConstantPoolCacheEntry::tos_state_shift); - ConstantPoolCacheEntry::verify_tos_state_shift(); + __ load_unsigned_byte(c_rarg3, Address(c_rarg2, in_bytes(ResolvedFieldEntry::type_offset()))); Label nope2, done, ok; __ ldr(c_rarg1, at_tos_p1()); // initially assume a one word jvalue __ cmpw(c_rarg3, ltos); @@ -2683,8 +2735,6 @@ void TemplateTable::jvmti_post_field_mod(Register cache, Register index, bool is __ ldr(c_rarg1, at_tos_p2()); // ltos (two word jvalue) __ bind(nope2); } - // cache entry pointer - __ add(c_rarg2, c_rarg2, in_bytes(cp_base_offset)); // object (tos) __ mov(c_rarg3, esp); // c_rarg1: object pointer set up above (null if static) @@ -2694,7 +2744,7 @@ void TemplateTable::jvmti_post_field_mod(Register cache, Register index, bool is CAST_FROM_FN_PTR(address, InterpreterRuntime::post_field_modification), c_rarg1, c_rarg2, c_rarg3); - __ get_cache_and_index_at_bcp(cache, index, 1); + __ load_field_entry(cache, index); __ bind(L1); } } @@ -2702,23 +2752,24 @@ void TemplateTable::jvmti_post_field_mod(Register cache, Register index, bool is void TemplateTable::putfield_or_static(int byte_no, bool is_static, RewriteControl rc) { transition(vtos, vtos); - const Register cache = r2; - const Register index = r3; - const Register obj = r2; - const Register off = r19; - const Register flags = r0; - const Register bc = r4; + const Register cache = r2; + const Register index = r3; + const Register tos_state = r3; + const Register obj = r2; + const Register off = r19; + const Register flags = r0; + const Register bc = r4; - resolve_cache_and_index(byte_no, cache, index, sizeof(u2)); + resolve_cache_and_index_for_field(byte_no, cache, index); jvmti_post_field_mod(cache, index, is_static); - load_field_cp_cache_entry(obj, cache, index, off, flags, is_static); + load_resolved_field_entry(obj, cache, tos_state, off, flags, is_static); Label Done; __ mov(r5, flags); { Label notVolatile; - __ tbz(r5, ConstantPoolCacheEntry::is_volatile_shift, notVolatile); + __ tbz(r5, ResolvedFieldEntry::is_volatile_shift, notVolatile); __ membar(MacroAssembler::StoreStore | MacroAssembler::LoadStore); __ bind(notVolatile); } @@ -2729,12 +2780,8 @@ void TemplateTable::putfield_or_static(int byte_no, bool is_static, RewriteContr Label notByte, notBool, notInt, notShort, notChar, notLong, notFloat, notObj, notDouble; - // x86 uses a shift and mask or wings it with a shift plus assert - // the mask is not needed. aarch64 just uses bitfield extract - __ ubfxw(flags, flags, ConstantPoolCacheEntry::tos_state_shift, ConstantPoolCacheEntry::tos_state_bits); - assert(btos == 0, "change code, btos != 0"); - __ cbnz(flags, notByte); + __ cbnz(tos_state, notByte); // Don't rewrite putstatic, only putfield if (is_static) rc = may_not_rewrite; @@ -2751,7 +2798,7 @@ void TemplateTable::putfield_or_static(int byte_no, bool is_static, RewriteContr } __ bind(notByte); - __ cmp(flags, (u1)ztos); + __ cmp(tos_state, (u1)ztos); __ br(Assembler::NE, notBool); // ztos @@ -2766,7 +2813,7 @@ void TemplateTable::putfield_or_static(int byte_no, bool is_static, RewriteContr } __ bind(notBool); - __ cmp(flags, (u1)atos); + __ cmp(tos_state, (u1)atos); __ br(Assembler::NE, notObj); // atos @@ -2782,7 +2829,7 @@ void TemplateTable::putfield_or_static(int byte_no, bool is_static, RewriteContr } __ bind(notObj); - __ cmp(flags, (u1)itos); + __ cmp(tos_state, (u1)itos); __ br(Assembler::NE, notInt); // itos @@ -2797,7 +2844,7 @@ void TemplateTable::putfield_or_static(int byte_no, bool is_static, RewriteContr } __ bind(notInt); - __ cmp(flags, (u1)ctos); + __ cmp(tos_state, (u1)ctos); __ br(Assembler::NE, notChar); // ctos @@ -2812,7 +2859,7 @@ void TemplateTable::putfield_or_static(int byte_no, bool is_static, RewriteContr } __ bind(notChar); - __ cmp(flags, (u1)stos); + __ cmp(tos_state, (u1)stos); __ br(Assembler::NE, notShort); // stos @@ -2827,7 +2874,7 @@ void TemplateTable::putfield_or_static(int byte_no, bool is_static, RewriteContr } __ bind(notShort); - __ cmp(flags, (u1)ltos); + __ cmp(tos_state, (u1)ltos); __ br(Assembler::NE, notLong); // ltos @@ -2842,7 +2889,7 @@ void TemplateTable::putfield_or_static(int byte_no, bool is_static, RewriteContr } __ bind(notLong); - __ cmp(flags, (u1)ftos); + __ cmp(tos_state, (u1)ftos); __ br(Assembler::NE, notFloat); // ftos @@ -2858,7 +2905,7 @@ void TemplateTable::putfield_or_static(int byte_no, bool is_static, RewriteContr __ bind(notFloat); #ifdef ASSERT - __ cmp(flags, (u1)dtos); + __ cmp(tos_state, (u1)dtos); __ br(Assembler::NE, notDouble); #endif @@ -2883,7 +2930,7 @@ void TemplateTable::putfield_or_static(int byte_no, bool is_static, RewriteContr { Label notVolatile; - __ tbz(r5, ConstantPoolCacheEntry::is_volatile_shift, notVolatile); + __ tbz(r5, ResolvedFieldEntry::is_volatile_shift, notVolatile); __ membar(MacroAssembler::StoreLoad | MacroAssembler::StoreStore); __ bind(notVolatile); } @@ -2902,8 +2949,7 @@ void TemplateTable::putstatic(int byte_no) { putfield_or_static(byte_no, true); } -void TemplateTable::jvmti_post_fast_field_mod() -{ +void TemplateTable::jvmti_post_fast_field_mod() { if (JvmtiExport::can_post_field_modification()) { // Check to see if a field modification watch has been set before // we take the time to call into the VM. @@ -2933,7 +2979,7 @@ void TemplateTable::jvmti_post_fast_field_mod() } __ mov(c_rarg3, esp); // points to jvalue on the stack // access constant pool cache entry - __ get_cache_entry_pointer_at_bcp(c_rarg2, r0, 1); + __ load_field_entry(c_rarg2, r0); __ verify_oop(r19); // r19: object pointer copied above // c_rarg2: cache entry pointer @@ -2968,21 +3014,18 @@ void TemplateTable::fast_storefield(TosState state) jvmti_post_fast_field_mod(); // access constant pool cache - __ get_cache_and_index_at_bcp(r2, r1, 1); + __ load_field_entry(r2, r1); + __ push(r0); + // R1: field offset, R2: TOS, R3: flags + load_resolved_field_entry(r2, r2, r0, r1, r3); + __ pop(r0); // Must prevent reordering of the following cp cache loads with bytecode load __ membar(MacroAssembler::LoadLoad); - // test for volatile with r3 - __ ldrw(r3, Address(r2, in_bytes(base + - ConstantPoolCacheEntry::flags_offset()))); - - // replace index with field offset from cache entry - __ ldr(r1, Address(r2, in_bytes(base + ConstantPoolCacheEntry::f2_offset()))); - { Label notVolatile; - __ tbz(r3, ConstantPoolCacheEntry::is_volatile_shift, notVolatile); + __ tbz(r3, ResolvedFieldEntry::is_volatile_shift, notVolatile); __ membar(MacroAssembler::StoreStore | MacroAssembler::LoadStore); __ bind(notVolatile); } @@ -3030,7 +3073,7 @@ void TemplateTable::fast_storefield(TosState state) { Label notVolatile; - __ tbz(r3, ConstantPoolCacheEntry::is_volatile_shift, notVolatile); + __ tbz(r3, ResolvedFieldEntry::is_volatile_shift, notVolatile); __ membar(MacroAssembler::StoreLoad | MacroAssembler::StoreStore); __ bind(notVolatile); } @@ -3049,7 +3092,7 @@ void TemplateTable::fast_accessfield(TosState state) __ ldrw(r2, Address(rscratch1)); __ cbzw(r2, L1); // access constant pool cache entry - __ get_cache_entry_pointer_at_bcp(c_rarg2, rscratch2, 1); + __ load_field_entry(c_rarg2, rscratch2); __ verify_oop(r0); __ push_ptr(r0); // save object pointer before call_VM() clobbers it __ mov(c_rarg1, r0); @@ -3064,15 +3107,13 @@ void TemplateTable::fast_accessfield(TosState state) } // access constant pool cache - __ get_cache_and_index_at_bcp(r2, r1, 1); + __ load_field_entry(r2, r1); // Must prevent reordering of the following cp cache loads with bytecode load __ membar(MacroAssembler::LoadLoad); - __ ldr(r1, Address(r2, in_bytes(ConstantPoolCache::base_offset() + - ConstantPoolCacheEntry::f2_offset()))); - __ ldrw(r3, Address(r2, in_bytes(ConstantPoolCache::base_offset() + - ConstantPoolCacheEntry::flags_offset()))); + __ load_sized_value(r1, Address(r2, in_bytes(ResolvedFieldEntry::field_offset_offset())), sizeof(int), true /*is_signed*/); + __ load_unsigned_byte(r3, Address(r2, in_bytes(ResolvedFieldEntry::flags_offset()))); // r0: object __ verify_oop(r0); @@ -3087,7 +3128,7 @@ void TemplateTable::fast_accessfield(TosState state) // the stores in one method and we interpret the loads in another. if (!CompilerConfig::is_c1_or_interpreter_only_no_jvmci()) { Label notVolatile; - __ tbz(r3, ConstantPoolCacheEntry::is_volatile_shift, notVolatile); + __ tbz(r3, ResolvedFieldEntry::is_volatile_shift, notVolatile); __ membar(MacroAssembler::AnyAny); __ bind(notVolatile); } @@ -3124,7 +3165,7 @@ void TemplateTable::fast_accessfield(TosState state) } { Label notVolatile; - __ tbz(r3, ConstantPoolCacheEntry::is_volatile_shift, notVolatile); + __ tbz(r3, ResolvedFieldEntry::is_volatile_shift, notVolatile); __ membar(MacroAssembler::LoadLoad | MacroAssembler::LoadStore); __ bind(notVolatile); } @@ -3137,9 +3178,8 @@ void TemplateTable::fast_xaccess(TosState state) // get receiver __ ldr(r0, aaddress(0)); // access constant pool cache - __ get_cache_and_index_at_bcp(r2, r3, 2); - __ ldr(r1, Address(r2, in_bytes(ConstantPoolCache::base_offset() + - ConstantPoolCacheEntry::f2_offset()))); + __ load_field_entry(r2, r3, 2); + __ load_sized_value(r1, Address(r2, in_bytes(ResolvedFieldEntry::field_offset_offset())), sizeof(int), true /*is_signed*/); // 8179954: We need to make sure that the code generated for // volatile accesses forms a sequentially-consistent set of @@ -3149,9 +3189,8 @@ void TemplateTable::fast_xaccess(TosState state) // the stores in one method and we interpret the loads in another. if (!CompilerConfig::is_c1_or_interpreter_only_no_jvmci()) { Label notVolatile; - __ ldrw(r3, Address(r2, in_bytes(ConstantPoolCache::base_offset() + - ConstantPoolCacheEntry::flags_offset()))); - __ tbz(r3, ConstantPoolCacheEntry::is_volatile_shift, notVolatile); + __ load_unsigned_byte(r3, Address(r2, in_bytes(ResolvedFieldEntry::flags_offset()))); + __ tbz(r3, ResolvedFieldEntry::is_volatile_shift, notVolatile); __ membar(MacroAssembler::AnyAny); __ bind(notVolatile); } @@ -3177,9 +3216,8 @@ void TemplateTable::fast_xaccess(TosState state) { Label notVolatile; - __ ldrw(r3, Address(r2, in_bytes(ConstantPoolCache::base_offset() + - ConstantPoolCacheEntry::flags_offset()))); - __ tbz(r3, ConstantPoolCacheEntry::is_volatile_shift, notVolatile); + __ load_unsigned_byte(r3, Address(r2, in_bytes(ResolvedFieldEntry::flags_offset()))); + __ tbz(r3, ResolvedFieldEntry::is_volatile_shift, notVolatile); __ membar(MacroAssembler::LoadLoad | MacroAssembler::LoadStore); __ bind(notVolatile); } diff --git a/src/hotspot/cpu/ppc/interp_masm_ppc.hpp b/src/hotspot/cpu/ppc/interp_masm_ppc.hpp index 928c48cdd17..c868816b278 100644 --- a/src/hotspot/cpu/ppc/interp_masm_ppc.hpp +++ b/src/hotspot/cpu/ppc/interp_masm_ppc.hpp @@ -128,6 +128,7 @@ class InterpreterMacroAssembler: public MacroAssembler { void get_cache_and_index_at_bcp(Register cache, int bcp_offset, size_t index_size = sizeof(u2)); void load_resolved_indy_entry(Register cache, Register index); + void load_field_entry(Register cache, Register index, int bcp_offset = 1); void get_u4(Register Rdst, Register Rsrc, int offset, signedOrNot is_signed); diff --git a/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp b/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp index 923fbf3ee93..2873fc2eca0 100644 --- a/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp +++ b/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp @@ -31,6 +31,7 @@ #include "interp_masm_ppc.hpp" #include "interpreter/interpreterRuntime.hpp" #include "oops/methodData.hpp" +#include "oops/resolvedFieldEntry.hpp" #include "oops/resolvedIndyEntry.hpp" #include "prims/jvmtiExport.hpp" #include "prims/jvmtiThreadState.hpp" @@ -487,11 +488,28 @@ void InterpreterMacroAssembler::load_resolved_indy_entry(Register cache, Registe // Get address of invokedynamic array ld_ptr(cache, in_bytes(ConstantPoolCache::invokedynamic_entries_offset()), R27_constPoolCache); - // Scale the index to be the entry index * sizeof(ResolvedInvokeDynamicInfo) + // Scale the index to be the entry index * sizeof(ResolvedIndyEntry) sldi(index, index, log2i_exact(sizeof(ResolvedIndyEntry))); add(cache, cache, index); } +void InterpreterMacroAssembler::load_field_entry(Register cache, Register index, int bcp_offset) { + // Get index out of bytecode pointer + get_cache_index_at_bcp(index, bcp_offset, sizeof(u2)); + // Take shortcut if the size is a power of 2 + if (is_power_of_2(sizeof(ResolvedFieldEntry))) { + // Scale index by power of 2 + sldi(index, index, log2i_exact(sizeof(ResolvedFieldEntry))); + } else { + // Scale the index to be the entry index * sizeof(ResolvedFieldEntry) + mulli(index, index, sizeof(ResolvedFieldEntry)); + } + // Get address of field entries array + ld_ptr(cache, in_bytes(ConstantPoolCache::field_entries_offset()), R27_constPoolCache); + addi(cache, cache, Array::base_offset_in_bytes()); + add(cache, cache, index); +} + // Load object from cpool->resolved_references(index). // Kills: // - index diff --git a/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp b/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp index 05de377984b..0995edc8615 100644 --- a/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp +++ b/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp @@ -38,6 +38,7 @@ #include "oops/methodData.hpp" #include "oops/objArrayKlass.hpp" #include "oops/oop.inline.hpp" +#include "oops/resolvedFieldEntry.hpp" #include "oops/resolvedIndyEntry.hpp" #include "prims/jvmtiExport.hpp" #include "prims/methodHandles.hpp" @@ -116,13 +117,10 @@ void TemplateTable::patch_bytecode(Bytecodes::Code new_bc, Register Rnew_bc, Reg // additional, required work. assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range"); assert(load_bc_into_bc_reg, "we use bc_reg as temp"); - __ get_cache_and_index_at_bcp(Rtemp /* dst = cache */, 1); - // ((*(cache+indices))>>((1+byte_no)*8))&0xFF: -#if defined(VM_LITTLE_ENDIAN) - __ lbz(Rnew_bc, in_bytes(ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::indices_offset()) + 1 + byte_no, Rtemp); -#else - __ lbz(Rnew_bc, in_bytes(ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::indices_offset()) + 7 - (1 + byte_no), Rtemp); -#endif + __ load_field_entry(Rtemp, Rnew_bc); + int code_offset = (byte_no == f1_byte) ? in_bytes(ResolvedFieldEntry::get_code_offset()) + : in_bytes(ResolvedFieldEntry::put_code_offset()); + __ lbz(Rnew_bc, code_offset, Rtemp); __ cmpwi(CCR0, Rnew_bc, 0); __ li(Rnew_bc, (unsigned int)(unsigned char)new_bc); __ beq(CCR0, L_patch_done); @@ -2247,6 +2245,68 @@ void TemplateTable::resolve_cache_and_index(int byte_no, Register Rcache, Regist __ bind(Ldone); } +void TemplateTable::resolve_cache_and_index_for_field(int byte_no, + Register Rcache, + Register index) { + assert_different_registers(Rcache, index); + + Label resolved; + + Bytecodes::Code code = bytecode(); + switch (code) { + case Bytecodes::_nofast_getfield: code = Bytecodes::_getfield; break; + case Bytecodes::_nofast_putfield: code = Bytecodes::_putfield; break; + default: break; + } + + assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range"); + __ load_field_entry(Rcache, index); + int code_offset = (byte_no == f1_byte) ? in_bytes(ResolvedFieldEntry::get_code_offset()) + : in_bytes(ResolvedFieldEntry::put_code_offset()); + __ lbz(R0, code_offset, Rcache); + __ cmpwi(CCR0, R0, (int)code); // have we resolved this bytecode? + __ beq(CCR0, resolved); + + // resolve first time through + address entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_from_cache); + __ li(R4_ARG2, (int)code); + __ call_VM(noreg, entry, R4_ARG2); + + // Update registers with resolved info + __ load_field_entry(Rcache, index); + __ bind(resolved); + + // Use acquire semantics for the bytecode (see ResolvedFieldEntry::fill_in()). + __ isync(); // Order load wrt. succeeding loads. +} + +void TemplateTable::load_resolved_field_entry(Register obj, + Register cache, + Register tos_state, + Register offset, + Register flags, + bool is_static = false) { + assert_different_registers(cache, tos_state, flags, offset); + + // Field offset + __ load_sized_value(offset, in_bytes(ResolvedFieldEntry::field_offset_offset()), cache, sizeof(int), true /*is_signed*/); + + // Flags + __ lbz(flags, in_bytes(ResolvedFieldEntry::flags_offset()), cache); + + if (tos_state != noreg) { + __ lbz(tos_state, in_bytes(ResolvedFieldEntry::type_offset()), cache); + } + + // Klass overwrite register + if (is_static) { + __ ld(obj, in_bytes(ResolvedFieldEntry::field_holder_offset()), cache); + const int mirror_offset = in_bytes(Klass::java_mirror_offset()); + __ ld(obj, mirror_offset, obj); + __ resolve_oop_handle(obj, R11_scratch1, R12_scratch2, MacroAssembler::PRESERVATION_NONE); + } +} + // Load the constant pool cache entry at field accesses into registers. // The Rcache and Rindex registers must be set before call. // Input: @@ -2432,7 +2492,6 @@ void TemplateTable::jvmti_post_field_access(Register Rcache, Register Rscratch, assert_different_registers(Rcache, Rscratch); if (JvmtiExport::can_post_field_access()) { - ByteSize cp_base_offset = ConstantPoolCache::base_offset(); Label Lno_field_access_post; // Check if post field access in enabled. @@ -2443,7 +2502,6 @@ void TemplateTable::jvmti_post_field_access(Register Rcache, Register Rscratch, __ beq(CCR0, Lno_field_access_post); // Post access enabled - do it! - __ addi(Rcache, Rcache, in_bytes(cp_base_offset)); if (is_static) { __ li(R17_tos, 0); } else { @@ -2467,7 +2525,7 @@ void TemplateTable::jvmti_post_field_access(Register Rcache, Register Rscratch, __ verify_oop(R17_tos); } else { // Cache is still needed to get class or obj. - __ get_cache_and_index_at_bcp(Rcache, 1); + __ load_field_entry(Rcache, Rscratch); } __ align(32, 12); @@ -2493,9 +2551,10 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteContr Label Lacquire, Lisync; const Register Rcache = R3_ARG1, - Rclass_or_obj = R22_tmp2, - Roffset = R23_tmp3, - Rflags = R31, + Rclass_or_obj = R22_tmp2, // Needs to survive C call. + Roffset = R23_tmp3, // Needs to survive C call. + Rtos_state = R30, // Needs to survive C call. + Rflags = R31, // Needs to survive C call. Rbtable = R5_ARG3, Rbc = R30, Rscratch = R11_scratch1; // used by load_field_cp_cache_entry @@ -2507,37 +2566,34 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteContr address* branch_table = (is_static || rc == may_not_rewrite) ? static_branch_table : field_branch_table; // Get field offset. - resolve_cache_and_index(byte_no, Rcache, Rscratch, sizeof(u2)); + resolve_cache_and_index_for_field(byte_no, Rcache, Rscratch); // JVMTI support jvmti_post_field_access(Rcache, Rscratch, is_static, false); // Load after possible GC. - load_field_cp_cache_entry(Rclass_or_obj, Rcache, noreg, Roffset, Rflags, is_static); // Uses R11, R12 + load_resolved_field_entry(Rclass_or_obj, Rcache, Rtos_state, Roffset, Rflags, is_static); // Uses R11, R12 // Load pointer to branch table. __ load_const_optimized(Rbtable, (address)branch_table, Rscratch); // Get volatile flag. - __ rldicl(Rscratch, Rflags, 64-ConstantPoolCacheEntry::is_volatile_shift, 63); // Extract volatile bit. + __ rldicl(Rscratch, Rflags, 64-ResolvedFieldEntry::is_volatile_shift, 63); // Extract volatile bit. // Note: sync is needed before volatile load on PPC64. - // Check field type. - __ rldicl(Rflags, Rflags, 64-ConstantPoolCacheEntry::tos_state_shift, 64-ConstantPoolCacheEntry::tos_state_bits); - #ifdef ASSERT Label LFlagInvalid; - __ cmpldi(CCR0, Rflags, number_of_states); + __ cmpldi(CCR0, Rtos_state, number_of_states); __ bge(CCR0, LFlagInvalid); #endif // Load from branch table and dispatch (volatile case: one instruction ahead). - __ sldi(Rflags, Rflags, LogBytesPerWord); + __ sldi(Rtos_state, Rtos_state, LogBytesPerWord); __ cmpwi(CCR2, Rscratch, 1); // Volatile? if (support_IRIW_for_not_multiple_copy_atomic_cpu) { __ sldi(Rscratch, Rscratch, exact_log2(BytesPerInstWord)); // Volatile ? size of 1 instruction : 0. } - __ ldx(Rbtable, Rbtable, Rflags); + __ ldx(Rbtable, Rbtable, Rtos_state); // Get the obj from stack. if (!is_static) { @@ -2753,10 +2809,8 @@ void TemplateTable::jvmti_post_field_mod(Register Rcache, Register Rscratch, boo __ beq(CCR0, Lno_field_mod_post); // Do the post - ByteSize cp_base_offset = ConstantPoolCache::base_offset(); const Register Robj = Rscratch; - __ addi(Rcache, Rcache, in_bytes(cp_base_offset)); if (is_static) { // Life is simple. Null out the object pointer. __ li(Robj, 0); @@ -2777,17 +2831,16 @@ void TemplateTable::jvmti_post_field_mod(Register Rcache, Register Rscratch, boo default: { offs = 0; base = Robj; - const Register Rflags = Robj; + const Register Rtos_state = Robj; Label is_one_slot; // Life is harder. The stack holds the value on top, followed by the // object. We don't know the size of the value, though; it could be // one or two words depending on its type. As a result, we must find // the type to determine where the object is. - __ ld(Rflags, in_bytes(ConstantPoolCacheEntry::flags_offset()), Rcache); // Big Endian - __ rldicl(Rflags, Rflags, 64-ConstantPoolCacheEntry::tos_state_shift, 64-ConstantPoolCacheEntry::tos_state_bits); + __ lbz(Rtos_state, in_bytes(ResolvedFieldEntry::type_offset()), Rcache); - __ cmpwi(CCR0, Rflags, ltos); - __ cmpwi(CCR1, Rflags, dtos); + __ cmpwi(CCR0, Rtos_state, ltos); + __ cmpwi(CCR1, Rtos_state, dtos); __ addi(base, R15_esp, Interpreter::expr_offset_in_bytes(1)); __ crnor(CCR0, Assembler::equal, CCR1, Assembler::equal); __ beq(CCR0, is_one_slot); @@ -2802,7 +2855,7 @@ void TemplateTable::jvmti_post_field_mod(Register Rcache, Register Rscratch, boo __ addi(R6_ARG4, R15_esp, Interpreter::expr_offset_in_bytes(0)); __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::post_field_modification), Robj, Rcache, R6_ARG4); - __ get_cache_and_index_at_bcp(Rcache, 1); + __ load_field_entry(Rcache, Rscratch); // In case of the fast versions, value lives in registers => put it back on tos. switch(bytecode()) { @@ -2830,7 +2883,8 @@ void TemplateTable::putfield_or_static(int byte_no, bool is_static, RewriteContr const Register Rcache = R5_ARG3, // Do not use ARG1/2 (causes trouble in jvmti_post_field_mod). Rclass_or_obj = R31, // Needs to survive C call. Roffset = R22_tmp2, // Needs to survive C call. - Rflags = R30, + Rtos_state = R23_tmp3, // Needs to survive C call. + Rflags = R30, // Needs to survive C call. Rbtable = R4_ARG2, Rscratch = R11_scratch1, // used by load_field_cp_cache_entry Rscratch2 = R12_scratch2, // used by load_field_cp_cache_entry @@ -2850,32 +2904,29 @@ void TemplateTable::putfield_or_static(int byte_no, bool is_static, RewriteContr // obj // Load the field offset. - resolve_cache_and_index(byte_no, Rcache, Rscratch, sizeof(u2)); + resolve_cache_and_index_for_field(byte_no, Rcache, Rscratch); jvmti_post_field_mod(Rcache, Rscratch, is_static); - load_field_cp_cache_entry(Rclass_or_obj, Rcache, noreg, Roffset, Rflags, is_static); // Uses R11, R12 + load_resolved_field_entry(Rclass_or_obj, Rcache, Rtos_state, Roffset, Rflags, is_static); // Uses R11, R12 // Load pointer to branch table. __ load_const_optimized(Rbtable, (address)branch_table, Rscratch); // Get volatile flag. - __ rldicl(Rscratch, Rflags, 64-ConstantPoolCacheEntry::is_volatile_shift, 63); // Extract volatile bit. - - // Check the field type. - __ rldicl(Rflags, Rflags, 64-ConstantPoolCacheEntry::tos_state_shift, 64-ConstantPoolCacheEntry::tos_state_bits); + __ rldicl(Rscratch, Rflags, 64-ResolvedFieldEntry::is_volatile_shift, 63); // Extract volatile bit. #ifdef ASSERT Label LFlagInvalid; - __ cmpldi(CCR0, Rflags, number_of_states); + __ cmpldi(CCR0, Rtos_state, number_of_states); __ bge(CCR0, LFlagInvalid); #endif // Load from branch table and dispatch (volatile case: one instruction ahead). - __ sldi(Rflags, Rflags, LogBytesPerWord); + __ sldi(Rtos_state, Rtos_state, LogBytesPerWord); if (!support_IRIW_for_not_multiple_copy_atomic_cpu) { __ cmpwi(CR_is_vol, Rscratch, 1); // Volatile? } __ sldi(Rscratch, Rscratch, exact_log2(BytesPerInstWord)); // Volatile? size of instruction 1 : 0. - __ ldx(Rbtable, Rbtable, Rflags); + __ ldx(Rbtable, Rbtable, Rtos_state); __ subf(Rbtable, Rscratch, Rbtable); // Point to volatile/non-volatile entry point. __ mtctr(Rbtable); @@ -3085,15 +3136,15 @@ void TemplateTable::fast_storefield(TosState state) { const ConditionRegister CR_is_vol = CCR2; // Non-volatile condition register (survives runtime call in do_oop_store). // Constant pool already resolved => Load flags and offset of field. - __ get_cache_and_index_at_bcp(Rcache, 1); + __ load_field_entry(Rcache, Rscratch); jvmti_post_field_mod(Rcache, Rscratch, false /* not static */); - load_field_cp_cache_entry(noreg, Rcache, noreg, Roffset, Rflags, false); // Uses R11, R12 + load_resolved_field_entry(noreg, Rcache, noreg, Roffset, Rflags, false); // Uses R11, R12 // Get the obj and the final store addr. pop_and_check_object(Rclass_or_obj); // Kills R11_scratch1. // Get volatile flag. - __ rldicl_(Rscratch, Rflags, 64-ConstantPoolCacheEntry::is_volatile_shift, 63); // Extract volatile bit. + __ rldicl_(Rscratch, Rflags, 64-ResolvedFieldEntry::is_volatile_shift, 63); // Extract volatile bit. if (!support_IRIW_for_not_multiple_copy_atomic_cpu) { __ cmpdi(CR_is_vol, Rscratch, 1); } { Label LnotVolatile; @@ -3166,8 +3217,8 @@ void TemplateTable::fast_accessfield(TosState state) { // R12_scratch2 used by load_field_cp_cache_entry // Constant pool already resolved. Get the field offset. - __ get_cache_and_index_at_bcp(Rcache, 1); - load_field_cp_cache_entry(noreg, Rcache, noreg, Roffset, Rflags, false); // Uses R11, R12 + __ load_field_entry(Rcache, Rscratch); + load_resolved_field_entry(noreg, Rcache, noreg, Roffset, Rflags, false); // Uses R11, R12 // JVMTI support jvmti_post_field_access(Rcache, Rscratch, false, true); @@ -3176,7 +3227,7 @@ void TemplateTable::fast_accessfield(TosState state) { __ null_check_throw(Rclass_or_obj, -1, Rscratch); // Get volatile flag. - __ rldicl_(Rscratch, Rflags, 64-ConstantPoolCacheEntry::is_volatile_shift, 63); // Extract volatile bit. + __ rldicl_(Rscratch, Rflags, 64-ResolvedFieldEntry::is_volatile_shift, 63); // Extract volatile bit. __ bne(CCR0, LisVolatile); switch(bytecode()) { @@ -3305,8 +3356,8 @@ void TemplateTable::fast_xaccess(TosState state) { __ ld(Rclass_or_obj, 0, R18_locals); // Constant pool already resolved. Get the field offset. - __ get_cache_and_index_at_bcp(Rcache, 2); - load_field_cp_cache_entry(noreg, Rcache, noreg, Roffset, Rflags, false); // Uses R11, R12 + __ load_field_entry(Rcache, Rscratch, 2); + load_resolved_field_entry(noreg, Rcache, noreg, Roffset, Rflags, false); // Uses R11, R12 // JVMTI support not needed, since we switch back to single bytecode as soon as debugger attaches. @@ -3317,7 +3368,7 @@ void TemplateTable::fast_xaccess(TosState state) { __ null_check_throw(Rclass_or_obj, -1, Rscratch); // Get volatile flag. - __ rldicl_(Rscratch, Rflags, 64-ConstantPoolCacheEntry::is_volatile_shift, 63); // Extract volatile bit. + __ rldicl_(Rscratch, Rflags, 64-ResolvedFieldEntry::is_volatile_shift, 63); // Extract volatile bit. __ bne(CCR0, LisVolatile); switch(state) { diff --git a/src/hotspot/cpu/riscv/interp_masm_riscv.cpp b/src/hotspot/cpu/riscv/interp_masm_riscv.cpp index 64d0b12b4e3..b8e155ccbba 100644 --- a/src/hotspot/cpu/riscv/interp_masm_riscv.cpp +++ b/src/hotspot/cpu/riscv/interp_masm_riscv.cpp @@ -36,6 +36,7 @@ #include "oops/markWord.hpp" #include "oops/method.hpp" #include "oops/methodData.hpp" +#include "oops/resolvedFieldEntry.hpp" #include "oops/resolvedIndyEntry.hpp" #include "prims/jvmtiExport.hpp" #include "prims/jvmtiThreadState.hpp" @@ -1986,13 +1987,30 @@ void InterpreterMacroAssembler::load_resolved_indy_entry(Register cache, Registe get_cache_index_at_bcp(index, cache, 1, sizeof(u4)); // Get address of invokedynamic array ld(cache, Address(xcpool, in_bytes(ConstantPoolCache::invokedynamic_entries_offset()))); - // Scale the index to be the entry index * sizeof(ResolvedInvokeDynamicInfo) + // Scale the index to be the entry index * sizeof(ResolvedIndyEntry) slli(index, index, log2i_exact(sizeof(ResolvedIndyEntry))); add(cache, cache, Array::base_offset_in_bytes()); add(cache, cache, index); la(cache, Address(cache, 0)); } +void InterpreterMacroAssembler::load_field_entry(Register cache, Register index, int bcp_offset) { + // Get index out of bytecode pointer + get_cache_index_at_bcp(index, cache, bcp_offset, sizeof(u2)); + // Take shortcut if the size is a power of 2 + if (is_power_of_2(sizeof(ResolvedFieldEntry))) { + slli(index, index, log2i_exact(sizeof(ResolvedFieldEntry))); // Scale index by power of 2 + } else { + mv(cache, sizeof(ResolvedFieldEntry)); + mul(index, index, cache); // Scale the index to be the entry index * sizeof(ResolvedIndyEntry) + } + // Get address of field entries array + ld(cache, Address(xcpool, ConstantPoolCache::field_entries_offset())); + add(cache, cache, Array::base_offset_in_bytes()); + add(cache, cache, index); + la(cache, Address(cache, 0)); +} + void InterpreterMacroAssembler::get_method_counters(Register method, Register mcs, Label& skip) { Label has_counters; diff --git a/src/hotspot/cpu/riscv/interp_masm_riscv.hpp b/src/hotspot/cpu/riscv/interp_masm_riscv.hpp index fbccf2401be..9b004cb081b 100644 --- a/src/hotspot/cpu/riscv/interp_masm_riscv.hpp +++ b/src/hotspot/cpu/riscv/interp_masm_riscv.hpp @@ -300,6 +300,7 @@ class InterpreterMacroAssembler: public MacroAssembler { } void load_resolved_indy_entry(Register cache, Register index); + void load_field_entry(Register cache, Register index, int bcp_offset = 1); #ifdef ASSERT void verify_access_flags(Register access_flags, uint32_t flag, diff --git a/src/hotspot/cpu/riscv/templateTable_riscv.cpp b/src/hotspot/cpu/riscv/templateTable_riscv.cpp index 836a0a06d2c..87efd3522d9 100644 --- a/src/hotspot/cpu/riscv/templateTable_riscv.cpp +++ b/src/hotspot/cpu/riscv/templateTable_riscv.cpp @@ -38,6 +38,7 @@ #include "oops/methodData.hpp" #include "oops/objArrayKlass.hpp" #include "oops/oop.inline.hpp" +#include "oops/resolvedFieldEntry.hpp" #include "oops/resolvedIndyEntry.hpp" #include "prims/jvmtiExport.hpp" #include "prims/methodHandles.hpp" @@ -169,7 +170,16 @@ void TemplateTable::patch_bytecode(Bytecodes::Code bc, Register bc_reg, // additional, required work. assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range"); assert(load_bc_into_bc_reg, "we use bc_reg as temp"); - __ get_cache_and_index_and_bytecode_at_bcp(temp_reg, bc_reg, temp_reg, byte_no, 1); + __ load_field_entry(temp_reg, bc_reg); + if (byte_no == f1_byte) { + __ la(temp_reg, Address(temp_reg, in_bytes(ResolvedFieldEntry::get_code_offset()))); + } else { + __ la(temp_reg, Address(temp_reg, in_bytes(ResolvedFieldEntry::put_code_offset()))); + } + // Load-acquire the bytecode to match store-release in ResolvedFieldEntry::fill_in() + __ membar(MacroAssembler::AnyAny); + __ lbu(temp_reg, Address(temp_reg, 0)); + __ membar(MacroAssembler::LoadLoad | MacroAssembler::LoadStore); __ mv(bc_reg, bc); __ beqz(temp_reg, L_patch_done); break; @@ -2155,11 +2165,6 @@ void TemplateTable::resolve_cache_and_index(int byte_no, Label resolved, clinit_barrier_slow; Bytecodes::Code code = bytecode(); - switch (code) { - case Bytecodes::_nofast_getfield: code = Bytecodes::_getfield; break; - case Bytecodes::_nofast_putfield: code = Bytecodes::_putfield; break; - default: break; - } assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range"); __ get_cache_and_index_and_bytecode_at_bcp(Rcache, index, temp, byte_no, 1, index_size); @@ -2188,6 +2193,71 @@ void TemplateTable::resolve_cache_and_index(int byte_no, } } +void TemplateTable::resolve_cache_and_index_for_field(int byte_no, + Register Rcache, + Register index) { + const Register temp = x9; + assert_different_registers(Rcache, index, temp); + + Label resolved; + + Bytecodes::Code code = bytecode(); + switch (code) { + case Bytecodes::_nofast_getfield: code = Bytecodes::_getfield; break; + case Bytecodes::_nofast_putfield: code = Bytecodes::_putfield; break; + default: break; + } + + assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range"); + __ load_field_entry(Rcache, index); + if (byte_no == f1_byte) { + __ la(temp, Address(Rcache, in_bytes(ResolvedFieldEntry::get_code_offset()))); + } else { + __ la(temp, Address(Rcache, in_bytes(ResolvedFieldEntry::put_code_offset()))); + } + // Load-acquire the bytecode to match store-release in ResolvedFieldEntry::fill_in() + __ membar(MacroAssembler::AnyAny); + __ lbu(temp, Address(temp, 0)); + __ membar(MacroAssembler::LoadLoad | MacroAssembler::LoadStore); + __ mv(t0, (int) code); // have we resolved this bytecode? + __ beq(temp, t0, resolved); + + // resolve first time through + address entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_from_cache); + __ mv(temp, (int) code); + __ call_VM(noreg, entry, temp); + + // Update registers with resolved info + __ load_field_entry(Rcache, index); + __ bind(resolved); +} + +void TemplateTable::load_resolved_field_entry(Register obj, + Register cache, + Register tos_state, + Register offset, + Register flags, + bool is_static = false) { + assert_different_registers(cache, tos_state, flags, offset); + + // Field offset + __ load_sized_value(offset, Address(cache, in_bytes(ResolvedFieldEntry::field_offset_offset())), sizeof(int), true /*is_signed*/); + + // Flags + __ load_unsigned_byte(flags, Address(cache, in_bytes(ResolvedFieldEntry::flags_offset()))); + + // TOS state + __ load_unsigned_byte(tos_state, Address(cache, in_bytes(ResolvedFieldEntry::type_offset()))); + + // Klass overwrite register + if (is_static) { + __ ld(obj, Address(cache, ResolvedFieldEntry::field_holder_offset())); + const int mirror_offset = in_bytes(Klass::java_mirror_offset()); + __ ld(obj, Address(obj, mirror_offset)); + __ resolve_oop_handle(obj, x15, t1); + } +} + // The Rcache and index registers must be set before call // n.b unlike x86 cache already includes the index offset void TemplateTable::load_field_cp_cache_entry(Register obj, @@ -2343,8 +2413,7 @@ void TemplateTable::jvmti_post_field_access(Register cache, Register index, __ beqz(x10, L1); - __ get_cache_and_index_at_bcp(c_rarg2, c_rarg3, 1); - __ la(c_rarg2, Address(c_rarg2, in_bytes(ConstantPoolCache::base_offset()))); + __ load_field_entry(c_rarg2, index); if (is_static) { __ mv(c_rarg1, zr); // null object reference @@ -2354,11 +2423,10 @@ void TemplateTable::jvmti_post_field_access(Register cache, Register index, } // c_rarg1: object pointer or null // c_rarg2: cache entry pointer - // c_rarg3: jvalue object on the stack __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::post_field_access), - c_rarg1, c_rarg2, c_rarg3); - __ get_cache_and_index_at_bcp(cache, index, 1); + c_rarg1, c_rarg2); + __ load_field_entry(cache, index); __ bind(L1); } } @@ -2370,17 +2438,17 @@ void TemplateTable::pop_and_check_object(Register r) { } void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteControl rc) { - const Register cache = x12; - const Register index = x13; + const Register cache = x14; const Register obj = x14; + const Register index = x13; + const Register tos_state = x13; const Register off = x9; - const Register flags = x10; - const Register raw_flags = x16; + const Register flags = x16; const Register bc = x14; // uses same reg as obj, so don't mix them - resolve_cache_and_index(byte_no, cache, index, sizeof(u2)); + resolve_cache_and_index_for_field(byte_no, cache, index); jvmti_post_field_access(cache, index, is_static, false); - load_field_cp_cache_entry(obj, cache, index, off, raw_flags, is_static); + load_resolved_field_entry(obj, cache, tos_state, off, flags, is_static); if (!is_static) { // obj is on the stack @@ -2393,12 +2461,8 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteContr Label Done, notByte, notBool, notInt, notShort, notChar, notLong, notFloat, notObj, notDouble; - __ slli(flags, raw_flags, XLEN - (ConstantPoolCacheEntry::tos_state_shift + - ConstantPoolCacheEntry::tos_state_bits)); - __ srli(flags, flags, XLEN - ConstantPoolCacheEntry::tos_state_bits); - assert(btos == 0, "change code, btos != 0"); - __ bnez(flags, notByte); + __ bnez(tos_state, notByte); // Don't rewrite getstatic, only getfield if (is_static) { @@ -2415,7 +2479,7 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteContr __ j(Done); __ bind(notByte); - __ sub(t0, flags, (u1)ztos); + __ sub(t0, tos_state, (u1)ztos); __ bnez(t0, notBool); // ztos (same code as btos) @@ -2429,7 +2493,7 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteContr __ j(Done); __ bind(notBool); - __ sub(t0, flags, (u1)atos); + __ sub(t0, tos_state, (u1)atos); __ bnez(t0, notObj); // atos do_oop_load(_masm, field, x10, IN_HEAP); @@ -2440,7 +2504,7 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteContr __ j(Done); __ bind(notObj); - __ sub(t0, flags, (u1)itos); + __ sub(t0, tos_state, (u1)itos); __ bnez(t0, notInt); // itos __ access_load_at(T_INT, IN_HEAP, x10, field, noreg, noreg); @@ -2453,7 +2517,7 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteContr __ j(Done); __ bind(notInt); - __ sub(t0, flags, (u1)ctos); + __ sub(t0, tos_state, (u1)ctos); __ bnez(t0, notChar); // ctos __ access_load_at(T_CHAR, IN_HEAP, x10, field, noreg, noreg); @@ -2465,7 +2529,7 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteContr __ j(Done); __ bind(notChar); - __ sub(t0, flags, (u1)stos); + __ sub(t0, tos_state, (u1)stos); __ bnez(t0, notShort); // stos __ access_load_at(T_SHORT, IN_HEAP, x10, field, noreg, noreg); @@ -2477,7 +2541,7 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteContr __ j(Done); __ bind(notShort); - __ sub(t0, flags, (u1)ltos); + __ sub(t0, tos_state, (u1)ltos); __ bnez(t0, notLong); // ltos __ access_load_at(T_LONG, IN_HEAP, x10, field, noreg, noreg); @@ -2489,7 +2553,7 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteContr __ j(Done); __ bind(notLong); - __ sub(t0, flags, (u1)ftos); + __ sub(t0, tos_state, (u1)ftos); __ bnez(t0, notFloat); // ftos __ access_load_at(T_FLOAT, IN_HEAP, noreg /* ftos */, field, noreg, noreg); @@ -2502,7 +2566,7 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteContr __ bind(notFloat); #ifdef ASSERT - __ sub(t0, flags, (u1)dtos); + __ sub(t0, tos_state, (u1)dtos); __ bnez(t0, notDouble); #endif // dtos @@ -2522,7 +2586,7 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteContr __ bind(Done); Label notVolatile; - __ test_bit(t0, raw_flags, ConstantPoolCacheEntry::is_volatile_shift); + __ test_bit(t0, flags, ResolvedFieldEntry::is_volatile_shift); __ beqz(t0, notVolatile); __ membar(MacroAssembler::LoadLoad | MacroAssembler::LoadStore); __ bind(notVolatile); @@ -2546,8 +2610,6 @@ void TemplateTable::getstatic(int byte_no) void TemplateTable::jvmti_post_field_mod(Register cache, Register index, bool is_static) { transition(vtos, vtos); - ByteSize cp_base_offset = ConstantPoolCache::base_offset(); - if (JvmtiExport::can_post_field_modification()) { // Check to see if a field modification watch has been set before // we take the time to call into the VM. @@ -2561,7 +2623,7 @@ void TemplateTable::jvmti_post_field_mod(Register cache, Register index, bool is }); __ beqz(x10, L1); - __ get_cache_and_index_at_bcp(c_rarg2, t0, 1); + __ mv(c_rarg2, cache); if (is_static) { // Life is simple. Null out the object pointer. @@ -2571,11 +2633,7 @@ void TemplateTable::jvmti_post_field_mod(Register cache, Register index, bool is // the object. We don't know the size of the value, though; it // could be one or two words depending on its type. As a result, // we must find the type to determine where the object is. - __ lwu(c_rarg3, Address(c_rarg2, - in_bytes(cp_base_offset + - ConstantPoolCacheEntry::flags_offset()))); - __ srli(c_rarg3, c_rarg3, ConstantPoolCacheEntry::tos_state_shift); - ConstantPoolCacheEntry::verify_tos_state_shift(); + __ load_unsigned_byte(c_rarg3, Address(c_rarg2, in_bytes(ResolvedFieldEntry::type_offset()))); Label nope2, done, ok; __ ld(c_rarg1, at_tos_p1()); // initially assume a one word jvalue __ sub(t0, c_rarg3, ltos); @@ -2586,8 +2644,6 @@ void TemplateTable::jvmti_post_field_mod(Register cache, Register index, bool is __ ld(c_rarg1, at_tos_p2()); // ltos (two word jvalue); __ bind(nope2); } - // cache entry pointer - __ add(c_rarg2, c_rarg2, in_bytes(cp_base_offset)); // object (tos) __ mv(c_rarg3, esp); // c_rarg1: object pointer set up above (null if static) @@ -2597,7 +2653,7 @@ void TemplateTable::jvmti_post_field_mod(Register cache, Register index, bool is CAST_FROM_FN_PTR(address, InterpreterRuntime::post_field_modification), c_rarg1, c_rarg2, c_rarg3); - __ get_cache_and_index_at_bcp(cache, index, 1); + __ load_field_entry(cache, index); __ bind(L1); } } @@ -2605,23 +2661,24 @@ void TemplateTable::jvmti_post_field_mod(Register cache, Register index, bool is void TemplateTable::putfield_or_static(int byte_no, bool is_static, RewriteControl rc) { transition(vtos, vtos); - const Register cache = x12; - const Register index = x13; - const Register obj = x12; - const Register off = x9; - const Register flags = x10; - const Register bc = x14; + const Register cache = x12; + const Register index = x13; + const Register tos_state = x13; + const Register obj = x12; + const Register off = x9; + const Register flags = x10; + const Register bc = x14; - resolve_cache_and_index(byte_no, cache, index, sizeof(u2)); + resolve_cache_and_index_for_field(byte_no, cache, index); jvmti_post_field_mod(cache, index, is_static); - load_field_cp_cache_entry(obj, cache, index, off, flags, is_static); + load_resolved_field_entry(obj, cache, tos_state, off, flags, is_static); Label Done; __ mv(x15, flags); { Label notVolatile; - __ test_bit(t0, x15, ConstantPoolCacheEntry::is_volatile_shift); + __ test_bit(t0, x15, ResolvedFieldEntry::is_volatile_shift); __ beqz(t0, notVolatile); __ membar(MacroAssembler::StoreStore | MacroAssembler::LoadStore); __ bind(notVolatile); @@ -2630,12 +2687,8 @@ void TemplateTable::putfield_or_static(int byte_no, bool is_static, RewriteContr Label notByte, notBool, notInt, notShort, notChar, notLong, notFloat, notObj, notDouble; - __ slli(flags, flags, XLEN - (ConstantPoolCacheEntry::tos_state_shift + - ConstantPoolCacheEntry::tos_state_bits)); - __ srli(flags, flags, XLEN - ConstantPoolCacheEntry::tos_state_bits); - assert(btos == 0, "change code, btos != 0"); - __ bnez(flags, notByte); + __ bnez(tos_state, notByte); // Don't rewrite putstatic, only putfield if (is_static) { @@ -2659,7 +2712,7 @@ void TemplateTable::putfield_or_static(int byte_no, bool is_static, RewriteContr } __ bind(notByte); - __ sub(t0, flags, (u1)ztos); + __ sub(t0, tos_state, (u1)ztos); __ bnez(t0, notBool); // ztos @@ -2679,7 +2732,7 @@ void TemplateTable::putfield_or_static(int byte_no, bool is_static, RewriteContr } __ bind(notBool); - __ sub(t0, flags, (u1)atos); + __ sub(t0, tos_state, (u1)atos); __ bnez(t0, notObj); // atos @@ -2700,7 +2753,7 @@ void TemplateTable::putfield_or_static(int byte_no, bool is_static, RewriteContr } __ bind(notObj); - __ sub(t0, flags, (u1)itos); + __ sub(t0, tos_state, (u1)itos); __ bnez(t0, notInt); // itos @@ -2720,7 +2773,7 @@ void TemplateTable::putfield_or_static(int byte_no, bool is_static, RewriteContr } __ bind(notInt); - __ sub(t0, flags, (u1)ctos); + __ sub(t0, tos_state, (u1)ctos); __ bnez(t0, notChar); // ctos @@ -2740,7 +2793,7 @@ void TemplateTable::putfield_or_static(int byte_no, bool is_static, RewriteContr } __ bind(notChar); - __ sub(t0, flags, (u1)stos); + __ sub(t0, tos_state, (u1)stos); __ bnez(t0, notShort); // stos @@ -2760,7 +2813,7 @@ void TemplateTable::putfield_or_static(int byte_no, bool is_static, RewriteContr } __ bind(notShort); - __ sub(t0, flags, (u1)ltos); + __ sub(t0, tos_state, (u1)ltos); __ bnez(t0, notLong); // ltos @@ -2780,7 +2833,7 @@ void TemplateTable::putfield_or_static(int byte_no, bool is_static, RewriteContr } __ bind(notLong); - __ sub(t0, flags, (u1)ftos); + __ sub(t0, tos_state, (u1)ftos); __ bnez(t0, notFloat); // ftos @@ -2801,7 +2854,7 @@ void TemplateTable::putfield_or_static(int byte_no, bool is_static, RewriteContr __ bind(notFloat); #ifdef ASSERT - __ sub(t0, flags, (u1)dtos); + __ sub(t0, tos_state, (u1)dtos); __ bnez(t0, notDouble); #endif @@ -2831,7 +2884,7 @@ void TemplateTable::putfield_or_static(int byte_no, bool is_static, RewriteContr { Label notVolatile; - __ test_bit(t0, x15, ConstantPoolCacheEntry::is_volatile_shift); + __ test_bit(t0, x15, ResolvedFieldEntry::is_volatile_shift); __ beqz(t0, notVolatile); __ membar(MacroAssembler::StoreLoad | MacroAssembler::StoreStore); __ bind(notVolatile); @@ -2884,7 +2937,7 @@ void TemplateTable::jvmti_post_fast_field_mod() { } __ mv(c_rarg3, esp); // points to jvalue on the stack // access constant pool cache entry - __ get_cache_entry_pointer_at_bcp(c_rarg2, x10, 1); + __ load_field_entry(c_rarg2, x10); __ verify_oop(x9); // x9: object pointer copied above // c_rarg2: cache entry pointer @@ -2918,21 +2971,18 @@ void TemplateTable::fast_storefield(TosState state) { jvmti_post_fast_field_mod(); // access constant pool cache - __ get_cache_and_index_at_bcp(x12, x11, 1); + __ load_field_entry(x12, x11); + __ push_reg(x10); + // X11: field offset, X12: TOS, X13: flags + load_resolved_field_entry(x12, x12, x10, x11, x13); + __ pop_reg(x10); // Must prevent reordering of the following cp cache loads with bytecode load __ membar(MacroAssembler::LoadLoad); - // test for volatile with x13 - __ lwu(x13, Address(x12, in_bytes(base + - ConstantPoolCacheEntry::flags_offset()))); - - // replace index with field offset from cache entry - __ ld(x11, Address(x12, in_bytes(base + ConstantPoolCacheEntry::f2_offset()))); - { Label notVolatile; - __ test_bit(t0, x13, ConstantPoolCacheEntry::is_volatile_shift); + __ test_bit(t0, x13, ResolvedFieldEntry::is_volatile_shift); __ beqz(t0, notVolatile); __ membar(MacroAssembler::StoreStore | MacroAssembler::LoadStore); __ bind(notVolatile); @@ -2980,7 +3030,7 @@ void TemplateTable::fast_storefield(TosState state) { { Label notVolatile; - __ test_bit(t0, x13, ConstantPoolCacheEntry::is_volatile_shift); + __ test_bit(t0, x13, ResolvedFieldEntry::is_volatile_shift); __ beqz(t0, notVolatile); __ membar(MacroAssembler::StoreLoad | MacroAssembler::StoreStore); __ bind(notVolatile); @@ -3002,7 +3052,7 @@ void TemplateTable::fast_accessfield(TosState state) { }); __ beqz(x12, L1); // access constant pool cache entry - __ get_cache_entry_pointer_at_bcp(c_rarg2, t1, 1); + __ load_field_entry(c_rarg2, t1); __ verify_oop(x10); __ push_ptr(x10); // save object pointer before call_VM() clobbers it __ mv(c_rarg1, x10); @@ -3017,15 +3067,13 @@ void TemplateTable::fast_accessfield(TosState state) { } // access constant pool cache - __ get_cache_and_index_at_bcp(x12, x11, 1); + __ load_field_entry(x12, x11); // Must prevent reordering of the following cp cache loads with bytecode load __ membar(MacroAssembler::LoadLoad); - __ ld(x11, Address(x12, in_bytes(ConstantPoolCache::base_offset() + - ConstantPoolCacheEntry::f2_offset()))); - __ lwu(x13, Address(x12, in_bytes(ConstantPoolCache::base_offset() + - ConstantPoolCacheEntry::flags_offset()))); + __ load_sized_value(x11, Address(x12, in_bytes(ResolvedFieldEntry::field_offset_offset())), sizeof(int), true /*is_signed*/); + __ load_unsigned_byte(x13, Address(x12, in_bytes(ResolvedFieldEntry::flags_offset()))); // x10: object __ verify_oop(x10); @@ -3066,7 +3114,7 @@ void TemplateTable::fast_accessfield(TosState state) { } { Label notVolatile; - __ test_bit(t0, x13, ConstantPoolCacheEntry::is_volatile_shift); + __ test_bit(t0, x13, ResolvedFieldEntry::is_volatile_shift); __ beqz(t0, notVolatile); __ membar(MacroAssembler::LoadLoad | MacroAssembler::LoadStore); __ bind(notVolatile); @@ -3079,9 +3127,8 @@ void TemplateTable::fast_xaccess(TosState state) { // get receiver __ ld(x10, aaddress(0)); // access constant pool cache - __ get_cache_and_index_at_bcp(x12, x13, 2); - __ ld(x11, Address(x12, in_bytes(ConstantPoolCache::base_offset() + - ConstantPoolCacheEntry::f2_offset()))); + __ load_field_entry(x12, x13, 2); + __ load_sized_value(x11, Address(x12, in_bytes(ResolvedFieldEntry::field_offset_offset())), sizeof(int), true /*is_signed*/); // make sure exception is reported in correct bcp range (getfield is // next instruction) @@ -3108,9 +3155,8 @@ void TemplateTable::fast_xaccess(TosState state) { { Label notVolatile; - __ lwu(x13, Address(x12, in_bytes(ConstantPoolCache::base_offset() + - ConstantPoolCacheEntry::flags_offset()))); - __ test_bit(t0, x13, ConstantPoolCacheEntry::is_volatile_shift); + __ load_unsigned_byte(x13, Address(x12, in_bytes(ResolvedFieldEntry::flags_offset()))); + __ test_bit(t0, x13, ResolvedFieldEntry::is_volatile_shift); __ beqz(t0, notVolatile); __ membar(MacroAssembler::LoadLoad | MacroAssembler::LoadStore); __ bind(notVolatile); diff --git a/src/hotspot/cpu/x86/interp_masm_x86.cpp b/src/hotspot/cpu/x86/interp_masm_x86.cpp index f51ed64c47e..caa07857f03 100644 --- a/src/hotspot/cpu/x86/interp_masm_x86.cpp +++ b/src/hotspot/cpu/x86/interp_masm_x86.cpp @@ -32,6 +32,7 @@ #include "oops/markWord.hpp" #include "oops/methodData.hpp" #include "oops/method.hpp" +#include "oops/resolvedFieldEntry.hpp" #include "oops/resolvedIndyEntry.hpp" #include "prims/jvmtiExport.hpp" #include "prims/jvmtiThreadState.hpp" @@ -2115,7 +2116,22 @@ void InterpreterMacroAssembler::load_resolved_indy_entry(Register cache, Registe if (is_power_of_2(sizeof(ResolvedIndyEntry))) { shll(index, log2i_exact(sizeof(ResolvedIndyEntry))); // Scale index by power of 2 } else { - imull(index, index, sizeof(ResolvedIndyEntry)); // Scale the index to be the entry index * sizeof(ResolvedInvokeDynamicInfo) + imull(index, index, sizeof(ResolvedIndyEntry)); // Scale the index to be the entry index * sizeof(ResolvedIndyEntry) } lea(cache, Address(cache, index, Address::times_1, Array::base_offset_in_bytes())); } + +void InterpreterMacroAssembler::load_field_entry(Register cache, Register index, int bcp_offset) { + // Get index out of bytecode pointer + movptr(cache, Address(rbp, frame::interpreter_frame_cache_offset * wordSize)); + get_cache_index_at_bcp(index, bcp_offset, sizeof(u2)); + + movptr(cache, Address(cache, ConstantPoolCache::field_entries_offset())); + // Take shortcut if the size is a power of 2 + if (is_power_of_2(sizeof(ResolvedFieldEntry))) { + shll(index, log2i_exact(sizeof(ResolvedFieldEntry))); // Scale index by power of 2 + } else { + imull(index, index, sizeof(ResolvedFieldEntry)); // Scale the index to be the entry index * sizeof(ResolvedFieldEntry) + } + lea(cache, Address(cache, index, Address::times_1, Array::base_offset_in_bytes())); +} diff --git a/src/hotspot/cpu/x86/interp_masm_x86.hpp b/src/hotspot/cpu/x86/interp_masm_x86.hpp index 16d003cacf3..4adddc407c8 100644 --- a/src/hotspot/cpu/x86/interp_masm_x86.hpp +++ b/src/hotspot/cpu/x86/interp_masm_x86.hpp @@ -307,7 +307,7 @@ class InterpreterMacroAssembler: public MacroAssembler { void profile_parameters_type(Register mdp, Register tmp1, Register tmp2); void load_resolved_indy_entry(Register cache, Register index); - + void load_field_entry(Register cache, Register index, int bcp_offset = 1); }; #endif // CPU_X86_INTERP_MASM_X86_HPP diff --git a/src/hotspot/cpu/x86/templateTable_x86.cpp b/src/hotspot/cpu/x86/templateTable_x86.cpp index 61e1e1bd50c..7eab81f9095 100644 --- a/src/hotspot/cpu/x86/templateTable_x86.cpp +++ b/src/hotspot/cpu/x86/templateTable_x86.cpp @@ -36,6 +36,7 @@ #include "oops/methodData.hpp" #include "oops/objArrayKlass.hpp" #include "oops/oop.inline.hpp" +#include "oops/resolvedFieldEntry.hpp" #include "oops/resolvedIndyEntry.hpp" #include "prims/jvmtiExport.hpp" #include "prims/methodHandles.hpp" @@ -197,7 +198,13 @@ void TemplateTable::patch_bytecode(Bytecodes::Code bc, Register bc_reg, // additional, required work. assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range"); assert(load_bc_into_bc_reg, "we use bc_reg as temp"); - __ get_cache_and_index_and_bytecode_at_bcp(temp_reg, bc_reg, temp_reg, byte_no, 1); + __ load_field_entry(temp_reg, bc_reg); + if (byte_no == f1_byte) { + __ load_unsigned_byte(temp_reg, Address(temp_reg, in_bytes(ResolvedFieldEntry::get_code_offset()))); + } else { + __ load_unsigned_byte(temp_reg, Address(temp_reg, in_bytes(ResolvedFieldEntry::put_code_offset()))); + } + __ movl(bc_reg, bc); __ cmpl(temp_reg, (int) 0); __ jcc(Assembler::zero, L_patch_done); // don't patch @@ -2656,11 +2663,6 @@ void TemplateTable::resolve_cache_and_index(int byte_no, Label resolved; Bytecodes::Code code = bytecode(); - switch (code) { - case Bytecodes::_nofast_getfield: code = Bytecodes::_getfield; break; - case Bytecodes::_nofast_putfield: code = Bytecodes::_putfield; break; - default: break; - } assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range"); __ get_cache_and_index_and_bytecode_at_bcp(cache, index, temp, byte_no, 1, index_size); @@ -2691,6 +2693,68 @@ void TemplateTable::resolve_cache_and_index(int byte_no, } } +void TemplateTable::resolve_cache_and_index_for_field(int byte_no, + Register cache, + Register index) { + const Register temp = rbx; + assert_different_registers(cache, index, temp); + + Label resolved; + + Bytecodes::Code code = bytecode(); + switch (code) { + case Bytecodes::_nofast_getfield: code = Bytecodes::_getfield; break; + case Bytecodes::_nofast_putfield: code = Bytecodes::_putfield; break; + default: break; + } + + assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range"); + __ load_field_entry(cache, index); + if (byte_no == f1_byte) { + __ load_unsigned_byte(temp, Address(cache, in_bytes(ResolvedFieldEntry::get_code_offset()))); + } else { + __ load_unsigned_byte(temp, Address(cache, in_bytes(ResolvedFieldEntry::put_code_offset()))); + } + __ cmpl(temp, code); // have we resolved this bytecode? + __ jcc(Assembler::equal, resolved); + + // resolve first time through + address entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_from_cache); + __ movl(temp, code); + __ call_VM(noreg, entry, temp); + // Update registers with resolved info + __ load_field_entry(cache, index); + + __ bind(resolved); +} + +void TemplateTable::load_resolved_field_entry(Register obj, + Register cache, + Register tos_state, + Register offset, + Register flags, + bool is_static = false) { + assert_different_registers(cache, tos_state, flags, offset); + + // Field offset + __ load_sized_value(offset, Address(cache, in_bytes(ResolvedFieldEntry::field_offset_offset())), sizeof(int), true /*is_signed*/); + + // Flags + __ load_unsigned_byte(flags, Address(cache, in_bytes(ResolvedFieldEntry::flags_offset()))); + + // TOS state + __ load_unsigned_byte(tos_state, Address(cache, in_bytes(ResolvedFieldEntry::type_offset()))); + + // Klass overwrite register + if (is_static) { + __ movptr(obj, Address(cache, ResolvedFieldEntry::field_holder_offset())); + const int mirror_offset = in_bytes(Klass::java_mirror_offset()); + __ movptr(obj, Address(obj, mirror_offset)); + __ resolve_oop_handle(obj, rscratch2); + } + +} + // The cache and index registers must be set before call void TemplateTable::load_field_cp_cache_entry(Register obj, Register cache, @@ -2838,9 +2902,7 @@ void TemplateTable::jvmti_post_field_access(Register cache, __ jcc(Assembler::zero, L1); // cache entry pointer - __ addptr(cache, in_bytes(ConstantPoolCache::base_offset())); - __ shll(index, LogBytesPerWord); - __ addptr(cache, index); + __ load_field_entry(cache, index); if (is_static) { __ xorptr(rax, rax); // null object reference } else { @@ -2851,8 +2913,9 @@ void TemplateTable::jvmti_post_field_access(Register cache, // rax,: object pointer or null // cache: cache entry pointer __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::post_field_access), - rax, cache); - __ get_cache_and_index_at_bcp(cache, index, 1); + rax, cache); + + __ load_field_entry(cache, index); __ bind(L1); } } @@ -2866,16 +2929,17 @@ void TemplateTable::pop_and_check_object(Register r) { void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteControl rc) { transition(vtos, vtos); + const Register obj = LP64_ONLY(c_rarg3) NOT_LP64(rcx); const Register cache = rcx; const Register index = rdx; - const Register obj = LP64_ONLY(c_rarg3) NOT_LP64(rcx); const Register off = rbx; - const Register flags = rax; + const Register tos_state = rax; + const Register flags = rdx; const Register bc = LP64_ONLY(c_rarg3) NOT_LP64(rcx); // uses same reg as obj, so don't mix them - resolve_cache_and_index(byte_no, cache, index, sizeof(u2)); + resolve_cache_and_index_for_field(byte_no, cache, index); jvmti_post_field_access(cache, index, is_static, false); - load_field_cp_cache_entry(obj, cache, index, off, flags, is_static); + load_resolved_field_entry(obj, cache, tos_state, off, flags, is_static); if (!is_static) pop_and_check_object(obj); @@ -2883,13 +2947,11 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteContr Label Done, notByte, notBool, notInt, notShort, notChar, notLong, notFloat, notObj; - __ shrl(flags, ConstantPoolCacheEntry::tos_state_shift); // Make sure we don't need to mask edx after the above shift assert(btos == 0, "change code, btos != 0"); - - __ andl(flags, ConstantPoolCacheEntry::tos_state_mask); - + __ testl(tos_state, tos_state); __ jcc(Assembler::notZero, notByte); + // btos __ access_load_at(T_BYTE, IN_HEAP, rax, field, noreg, noreg); __ push(btos); @@ -2900,7 +2962,7 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteContr __ jmp(Done); __ bind(notByte); - __ cmpl(flags, ztos); + __ cmpl(tos_state, ztos); __ jcc(Assembler::notEqual, notBool); // ztos (same code as btos) @@ -2914,7 +2976,7 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteContr __ jmp(Done); __ bind(notBool); - __ cmpl(flags, atos); + __ cmpl(tos_state, atos); __ jcc(Assembler::notEqual, notObj); // atos do_oop_load(_masm, field, rax); @@ -2925,7 +2987,7 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteContr __ jmp(Done); __ bind(notObj); - __ cmpl(flags, itos); + __ cmpl(tos_state, itos); __ jcc(Assembler::notEqual, notInt); // itos __ access_load_at(T_INT, IN_HEAP, rax, field, noreg, noreg); @@ -2937,7 +2999,7 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteContr __ jmp(Done); __ bind(notInt); - __ cmpl(flags, ctos); + __ cmpl(tos_state, ctos); __ jcc(Assembler::notEqual, notChar); // ctos __ access_load_at(T_CHAR, IN_HEAP, rax, field, noreg, noreg); @@ -2949,7 +3011,7 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteContr __ jmp(Done); __ bind(notChar); - __ cmpl(flags, stos); + __ cmpl(tos_state, stos); __ jcc(Assembler::notEqual, notShort); // stos __ access_load_at(T_SHORT, IN_HEAP, rax, field, noreg, noreg); @@ -2961,7 +3023,7 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteContr __ jmp(Done); __ bind(notShort); - __ cmpl(flags, ltos); + __ cmpl(tos_state, ltos); __ jcc(Assembler::notEqual, notLong); // ltos // Generate code as if volatile (x86_32). There just aren't enough registers to @@ -2973,7 +3035,7 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteContr __ jmp(Done); __ bind(notLong); - __ cmpl(flags, ftos); + __ cmpl(tos_state, ftos); __ jcc(Assembler::notEqual, notFloat); // ftos @@ -2988,7 +3050,7 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteContr __ bind(notFloat); #ifdef ASSERT Label notDouble; - __ cmpl(flags, dtos); + __ cmpl(tos_state, dtos); __ jcc(Assembler::notEqual, notDouble); #endif // dtos @@ -3028,29 +3090,25 @@ void TemplateTable::getstatic(int byte_no) { // The registers cache and index expected to be set before call. // The function may destroy various registers, just not the cache and index registers. void TemplateTable::jvmti_post_field_mod(Register cache, Register index, bool is_static) { - - const Register robj = LP64_ONLY(c_rarg2) NOT_LP64(rax); - const Register RBX = LP64_ONLY(c_rarg1) NOT_LP64(rbx); - const Register RCX = LP64_ONLY(c_rarg3) NOT_LP64(rcx); - const Register RDX = LP64_ONLY(rscratch1) NOT_LP64(rdx); - - ByteSize cp_base_offset = ConstantPoolCache::base_offset(); + // Cache is rcx and index is rdx + const Register entry = LP64_ONLY(c_rarg2) NOT_LP64(rax); // ResolvedFieldEntry + const Register obj = LP64_ONLY(c_rarg1) NOT_LP64(rbx); // Object pointer + const Register value = LP64_ONLY(c_rarg3) NOT_LP64(rcx); // JValue object if (JvmtiExport::can_post_field_modification()) { // Check to see if a field modification watch has been set before // we take the time to call into the VM. Label L1; - assert_different_registers(cache, index, rax); + assert_different_registers(cache, obj, rax); __ mov32(rax, ExternalAddress((address)JvmtiExport::get_field_modification_count_addr())); __ testl(rax, rax); __ jcc(Assembler::zero, L1); - __ get_cache_and_index_at_bcp(robj, RDX, 1); - + __ mov(entry, cache); if (is_static) { // Life is simple. Null out the object pointer. - __ xorl(RBX, RBX); + __ xorl(obj, obj); } else { // Life is harder. The stack holds the value on top, followed by @@ -3060,53 +3118,44 @@ void TemplateTable::jvmti_post_field_mod(Register cache, Register index, bool is #ifndef _LP64 Label two_word, valsize_known; #endif - __ movl(RCX, Address(robj, RDX, - Address::times_ptr, - in_bytes(cp_base_offset + - ConstantPoolCacheEntry::flags_offset()))); - NOT_LP64(__ mov(rbx, rsp)); - __ shrl(RCX, ConstantPoolCacheEntry::tos_state_shift); - - // Make sure we don't need to mask rcx after the above shift - ConstantPoolCacheEntry::verify_tos_state_shift(); + __ load_unsigned_byte(value, Address(entry, in_bytes(ResolvedFieldEntry::type_offset()))); #ifdef _LP64 - __ movptr(c_rarg1, at_tos_p1()); // initially assume a one word jvalue - __ cmpl(c_rarg3, ltos); + __ movptr(obj, at_tos_p1()); // initially assume a one word jvalue + __ cmpl(value, ltos); __ cmovptr(Assembler::equal, - c_rarg1, at_tos_p2()); // ltos (two word jvalue) - __ cmpl(c_rarg3, dtos); + obj, at_tos_p2()); // ltos (two word jvalue) + __ cmpl(value, dtos); __ cmovptr(Assembler::equal, - c_rarg1, at_tos_p2()); // dtos (two word jvalue) + obj, at_tos_p2()); // dtos (two word jvalue) #else - __ cmpl(rcx, ltos); + __ mov(obj, rsp); + __ cmpl(value, ltos); __ jccb(Assembler::equal, two_word); - __ cmpl(rcx, dtos); + __ cmpl(value, dtos); __ jccb(Assembler::equal, two_word); - __ addptr(rbx, Interpreter::expr_offset_in_bytes(1)); // one word jvalue (not ltos, dtos) + __ addptr(obj, Interpreter::expr_offset_in_bytes(1)); // one word jvalue (not ltos, dtos) __ jmpb(valsize_known); __ bind(two_word); - __ addptr(rbx, Interpreter::expr_offset_in_bytes(2)); // two words jvalue + __ addptr(obj, Interpreter::expr_offset_in_bytes(2)); // two words jvalue __ bind(valsize_known); // setup object pointer - __ movptr(rbx, Address(rbx, 0)); + __ movptr(obj, Address(obj, 0)); #endif } - // cache entry pointer - __ addptr(robj, in_bytes(cp_base_offset)); - __ shll(RDX, LogBytesPerWord); - __ addptr(robj, RDX); + // object (tos) - __ mov(RCX, rsp); - // c_rarg1: object pointer set up above (null if static) - // c_rarg2: cache entry pointer - // c_rarg3: jvalue object on the stack + __ mov(value, rsp); + // obj: object pointer set up above (null if static) + // cache: field entry pointer + // value: jvalue object on the stack __ call_VM(noreg, - CAST_FROM_FN_PTR(address, - InterpreterRuntime::post_field_modification), - RBX, robj, RCX); - __ get_cache_and_index_at_bcp(cache, index, 1); + CAST_FROM_FN_PTR(address, + InterpreterRuntime::post_field_modification), + obj, entry, value); + // Reload field entry + __ load_field_entry(cache, index); __ bind(L1); } } @@ -3114,42 +3163,41 @@ void TemplateTable::jvmti_post_field_mod(Register cache, Register index, bool is void TemplateTable::putfield_or_static(int byte_no, bool is_static, RewriteControl rc) { transition(vtos, vtos); + const Register obj = rcx; const Register cache = rcx; const Register index = rdx; - const Register obj = rcx; + const Register tos_state = rdx; const Register off = rbx; const Register flags = rax; - resolve_cache_and_index(byte_no, cache, index, sizeof(u2)); + resolve_cache_and_index_for_field(byte_no, cache, index); jvmti_post_field_mod(cache, index, is_static); - load_field_cp_cache_entry(obj, cache, index, off, flags, is_static); + load_resolved_field_entry(obj, cache, tos_state, off, flags, is_static); // [jk] not needed currently // volatile_barrier(Assembler::Membar_mask_bits(Assembler::LoadStore | // Assembler::StoreStore)); Label notVolatile, Done; - __ movl(rdx, flags); - __ shrl(rdx, ConstantPoolCacheEntry::is_volatile_shift); - __ andl(rdx, 0x1); // Check for volatile store - __ testl(rdx, rdx); + __ andl(flags, (1 << ResolvedFieldEntry::is_volatile_shift)); + __ testl(flags, flags); __ jcc(Assembler::zero, notVolatile); - putfield_or_static_helper(byte_no, is_static, rc, obj, off, flags); + putfield_or_static_helper(byte_no, is_static, rc, obj, off, tos_state); volatile_barrier(Assembler::Membar_mask_bits(Assembler::StoreLoad | Assembler::StoreStore)); __ jmp(Done); __ bind(notVolatile); - putfield_or_static_helper(byte_no, is_static, rc, obj, off, flags); + putfield_or_static_helper(byte_no, is_static, rc, obj, off, tos_state); __ bind(Done); } void TemplateTable::putfield_or_static_helper(int byte_no, bool is_static, RewriteControl rc, - Register obj, Register off, Register flags) { + Register obj, Register off, Register tos_state) { // field addresses const Address field(obj, off, Address::times_1, 0*wordSize); @@ -3161,10 +3209,8 @@ void TemplateTable::putfield_or_static_helper(int byte_no, bool is_static, Rewri const Register bc = LP64_ONLY(c_rarg3) NOT_LP64(rcx); - __ shrl(flags, ConstantPoolCacheEntry::tos_state_shift); - - assert(btos == 0, "change code, btos != 0"); - __ andl(flags, ConstantPoolCacheEntry::tos_state_mask); + // Test TOS state + __ testl(tos_state, tos_state); __ jcc(Assembler::notZero, notByte); // btos @@ -3179,7 +3225,7 @@ void TemplateTable::putfield_or_static_helper(int byte_no, bool is_static, Rewri } __ bind(notByte); - __ cmpl(flags, ztos); + __ cmpl(tos_state, ztos); __ jcc(Assembler::notEqual, notBool); // ztos @@ -3194,7 +3240,7 @@ void TemplateTable::putfield_or_static_helper(int byte_no, bool is_static, Rewri } __ bind(notBool); - __ cmpl(flags, atos); + __ cmpl(tos_state, atos); __ jcc(Assembler::notEqual, notObj); // atos @@ -3210,7 +3256,7 @@ void TemplateTable::putfield_or_static_helper(int byte_no, bool is_static, Rewri } __ bind(notObj); - __ cmpl(flags, itos); + __ cmpl(tos_state, itos); __ jcc(Assembler::notEqual, notInt); // itos @@ -3225,7 +3271,7 @@ void TemplateTable::putfield_or_static_helper(int byte_no, bool is_static, Rewri } __ bind(notInt); - __ cmpl(flags, ctos); + __ cmpl(tos_state, ctos); __ jcc(Assembler::notEqual, notChar); // ctos @@ -3240,7 +3286,7 @@ void TemplateTable::putfield_or_static_helper(int byte_no, bool is_static, Rewri } __ bind(notChar); - __ cmpl(flags, stos); + __ cmpl(tos_state, stos); __ jcc(Assembler::notEqual, notShort); // stos @@ -3255,7 +3301,7 @@ void TemplateTable::putfield_or_static_helper(int byte_no, bool is_static, Rewri } __ bind(notShort); - __ cmpl(flags, ltos); + __ cmpl(tos_state, ltos); __ jcc(Assembler::notEqual, notLong); // ltos @@ -3273,7 +3319,7 @@ void TemplateTable::putfield_or_static_helper(int byte_no, bool is_static, Rewri } __ bind(notLong); - __ cmpl(flags, ftos); + __ cmpl(tos_state, ftos); __ jcc(Assembler::notEqual, notFloat); // ftos @@ -3290,7 +3336,7 @@ void TemplateTable::putfield_or_static_helper(int byte_no, bool is_static, Rewri __ bind(notFloat); #ifdef ASSERT Label notDouble; - __ cmpl(flags, dtos); + __ cmpl(tos_state, dtos); __ jcc(Assembler::notEqual, notDouble); #endif @@ -3360,8 +3406,8 @@ void TemplateTable::jvmti_post_fast_field_mod() { } __ mov(scratch, rsp); // points to jvalue on the stack // access constant pool cache entry - LP64_ONLY(__ get_cache_entry_pointer_at_bcp(c_rarg2, rax, 1)); - NOT_LP64(__ get_cache_entry_pointer_at_bcp(rax, rdx, 1)); + LP64_ONLY(__ load_field_entry(c_rarg2, rax)); + NOT_LP64(__ load_field_entry(rax, rdx)); __ verify_oop(rbx); // rbx: object pointer copied above // c_rarg2: cache entry pointer @@ -3388,29 +3434,18 @@ void TemplateTable::jvmti_post_fast_field_mod() { void TemplateTable::fast_storefield(TosState state) { transition(state, vtos); - ByteSize base = ConstantPoolCache::base_offset(); - - jvmti_post_fast_field_mod(); + Register cache = rcx; - // access constant pool cache - __ get_cache_and_index_at_bcp(rcx, rbx, 1); - - // test for volatile with rdx but rdx is tos register for lputfield. - __ movl(rdx, Address(rcx, rbx, Address::times_ptr, - in_bytes(base + - ConstantPoolCacheEntry::flags_offset()))); - - // replace index with field offset from cache entry - __ movptr(rbx, Address(rcx, rbx, Address::times_ptr, - in_bytes(base + ConstantPoolCacheEntry::f2_offset()))); + Label notVolatile, Done; - // [jk] not needed currently - // volatile_barrier(Assembler::Membar_mask_bits(Assembler::LoadStore | - // Assembler::StoreStore)); + jvmti_post_fast_field_mod(); - Label notVolatile, Done; - __ shrl(rdx, ConstantPoolCacheEntry::is_volatile_shift); - __ andl(rdx, 0x1); + __ push(rax); + __ load_field_entry(rcx, rax); + load_resolved_field_entry(noreg, cache, rax, rbx, rdx); + // RBX: field offset, RCX: RAX: TOS, RDX: flags + __ andl(rdx, (1 << ResolvedFieldEntry::is_volatile_shift)); + __ pop(rax); // Get object from stack pop_and_check_object(rcx); @@ -3485,8 +3520,8 @@ void TemplateTable::fast_accessfield(TosState state) { __ testl(rcx, rcx); __ jcc(Assembler::zero, L1); // access constant pool cache entry - LP64_ONLY(__ get_cache_entry_pointer_at_bcp(c_rarg2, rcx, 1)); - NOT_LP64(__ get_cache_entry_pointer_at_bcp(rcx, rdx, 1)); + LP64_ONLY(__ load_field_entry(c_rarg2, rcx)); + NOT_LP64(__ load_field_entry(rcx, rdx)); __ verify_oop(rax); __ push_ptr(rax); // save object pointer before call_VM() clobbers it LP64_ONLY(__ mov(c_rarg1, rax)); @@ -3499,18 +3534,8 @@ void TemplateTable::fast_accessfield(TosState state) { } // access constant pool cache - __ get_cache_and_index_at_bcp(rcx, rbx, 1); - // replace index with field offset from cache entry - // [jk] not needed currently - // __ movl(rdx, Address(rcx, rbx, Address::times_8, - // in_bytes(ConstantPoolCache::base_offset() + - // ConstantPoolCacheEntry::flags_offset()))); - // __ shrl(rdx, ConstantPoolCacheEntry::is_volatile_shift); - // __ andl(rdx, 0x1); - // - __ movptr(rbx, Address(rcx, rbx, Address::times_ptr, - in_bytes(ConstantPoolCache::base_offset() + - ConstantPoolCacheEntry::f2_offset()))); + __ load_field_entry(rcx, rbx); + __ load_sized_value(rbx, Address(rcx, in_bytes(ResolvedFieldEntry::field_offset_offset())), sizeof(int), true /*is_signed*/); // rax: object __ verify_oop(rax); @@ -3565,11 +3590,9 @@ void TemplateTable::fast_xaccess(TosState state) { // get receiver __ movptr(rax, aaddress(0)); // access constant pool cache - __ get_cache_and_index_at_bcp(rcx, rdx, 2); - __ movptr(rbx, - Address(rcx, rdx, Address::times_ptr, - in_bytes(ConstantPoolCache::base_offset() + - ConstantPoolCacheEntry::f2_offset()))); + __ load_field_entry(rcx, rdx, 2); + __ load_sized_value(rbx, Address(rcx, in_bytes(ResolvedFieldEntry::field_offset_offset())), sizeof(int), true /*is_signed*/); + // make sure exception is reported in correct bcp range (getfield is // next instruction) __ increment(rbcp); diff --git a/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp b/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp index d92b43f0ea5..9e00b1c5b04 100644 --- a/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp +++ b/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp @@ -605,7 +605,7 @@ int ZeroInterpreter::getter_entry(Method* method, intptr_t UNUSED, TRAPS) { // Get the entry from the constant pool cache, and drop into // the slow path if it has not been resolved ConstantPoolCache* cache = method->constants()->cache(); - ConstantPoolCacheEntry* entry = cache->entry_at(index); + ResolvedFieldEntry* entry = cache->resolved_field_entry_at(index); if (!entry->is_resolved(Bytecodes::_getfield)) { return normal_entry(method, 0, THREAD); } @@ -622,7 +622,7 @@ int ZeroInterpreter::getter_entry(Method* method, intptr_t UNUSED, TRAPS) { // If needed, allocate additional slot on stack: we already have one // for receiver, and double/long need another one. - switch (entry->flag_state()) { + switch (entry->tos_state()) { case ltos: case dtos: stack->overflow_check(1, CHECK_0); @@ -634,12 +634,12 @@ int ZeroInterpreter::getter_entry(Method* method, intptr_t UNUSED, TRAPS) { } // Read the field to stack(0) - int offset = entry->f2_as_index(); + int offset = entry->field_offset(); if (entry->is_volatile()) { if (support_IRIW_for_not_multiple_copy_atomic_cpu) { OrderAccess::fence(); } - switch (entry->flag_state()) { + switch (entry->tos_state()) { case btos: case ztos: SET_STACK_INT(object->byte_field_acquire(offset), 0); break; case ctos: SET_STACK_INT(object->char_field_acquire(offset), 0); break; @@ -653,7 +653,7 @@ int ZeroInterpreter::getter_entry(Method* method, intptr_t UNUSED, TRAPS) { ShouldNotReachHere(); } } else { - switch (entry->flag_state()) { + switch (entry->tos_state()) { case btos: case ztos: SET_STACK_INT(object->byte_field(offset), 0); break; case ctos: SET_STACK_INT(object->char_field(offset), 0); break; @@ -696,7 +696,7 @@ int ZeroInterpreter::setter_entry(Method* method, intptr_t UNUSED, TRAPS) { // Get the entry from the constant pool cache, and drop into // the slow path if it has not been resolved ConstantPoolCache* cache = method->constants()->cache(); - ConstantPoolCacheEntry* entry = cache->entry_at(index); + ResolvedFieldEntry* entry = cache->resolved_field_entry_at(index); if (!entry->is_resolved(Bytecodes::_putfield)) { return normal_entry(method, 0, THREAD); } @@ -707,7 +707,7 @@ int ZeroInterpreter::setter_entry(Method* method, intptr_t UNUSED, TRAPS) { // Figure out where the receiver is. If there is a long/double // operand on stack top, then receiver is two slots down. oop object = nullptr; - switch (entry->flag_state()) { + switch (entry->tos_state()) { case ltos: case dtos: object = STACK_OBJECT(-2); @@ -724,9 +724,9 @@ int ZeroInterpreter::setter_entry(Method* method, intptr_t UNUSED, TRAPS) { } // Store the stack(0) to field - int offset = entry->f2_as_index(); + int offset = entry->field_offset(); if (entry->is_volatile()) { - switch (entry->flag_state()) { + switch (entry->tos_state()) { case btos: object->release_byte_field_put(offset, STACK_INT(0)); break; case ztos: object->release_byte_field_put(offset, STACK_INT(0) & 1); break; // only store LSB case ctos: object->release_char_field_put(offset, STACK_INT(0)); break; @@ -741,7 +741,7 @@ int ZeroInterpreter::setter_entry(Method* method, intptr_t UNUSED, TRAPS) { } OrderAccess::storeload(); } else { - switch (entry->flag_state()) { + switch (entry->tos_state()) { case btos: object->byte_field_put(offset, STACK_INT(0)); break; case ztos: object->byte_field_put(offset, STACK_INT(0) & 1); break; // only store LSB case ctos: object->char_field_put(offset, STACK_INT(0)); break; diff --git a/src/hotspot/share/ci/ciStreams.cpp b/src/hotspot/share/ci/ciStreams.cpp index 9d88638f9e4..0348eb033ad 100644 --- a/src/hotspot/share/ci/ciStreams.cpp +++ b/src/hotspot/share/ci/ciStreams.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2023, 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 @@ -298,7 +298,7 @@ int ciBytecodeStream::get_field_index() { cur_bc() == Bytecodes::_putfield || cur_bc() == Bytecodes::_getstatic || cur_bc() == Bytecodes::_putstatic, "wrong bc"); - return get_index_u2_cpcache(); + return get_index_u2(); } diff --git a/src/hotspot/share/interpreter/bytecode.cpp b/src/hotspot/share/interpreter/bytecode.cpp index ff24ee5e088..cbdf8987cb0 100644 --- a/src/hotspot/share/interpreter/bytecode.cpp +++ b/src/hotspot/share/interpreter/bytecode.cpp @@ -136,7 +136,7 @@ Symbol* Bytecode_member_ref::klass() const { Symbol* Bytecode_member_ref::name() const { - return constants()->name_ref_at(index(), _code); + return constants()->name_ref_at(index(), Bytecodes::java_code(_code)); } @@ -164,6 +164,8 @@ int Bytecode_member_ref::index() const { Bytecodes::Code rawc = code(); if (has_index_u4(rawc)) return get_index_u4(rawc); + else if (Bytecodes::is_field_code(rawc)) + return get_index_u2(rawc); else return get_index_u2_cpcache(rawc); } diff --git a/src/hotspot/share/interpreter/bytecodeTracer.cpp b/src/hotspot/share/interpreter/bytecodeTracer.cpp index 8aa3abd4657..432138e7d69 100644 --- a/src/hotspot/share/interpreter/bytecodeTracer.cpp +++ b/src/hotspot/share/interpreter/bytecodeTracer.cpp @@ -35,6 +35,7 @@ #include "oops/constantPool.inline.hpp" #include "oops/methodData.hpp" #include "oops/method.hpp" +#include "oops/resolvedFieldEntry.hpp" #include "oops/resolvedIndyEntry.hpp" #include "runtime/handles.inline.hpp" #include "runtime/mutexLocker.hpp" @@ -501,8 +502,8 @@ void BytecodePrinter::print_attributes(int bci, outputStream* st) { { int cp_index; if (is_linked()) { - int cpcache_index = get_native_index_u2(); - cp_index = cpcache()->entry_at(cpcache_index)->constant_pool_index(); + int field_index = get_native_index_u2(); + cp_index = cpcache()->resolved_field_entry_at(field_index)->constant_pool_index(); } else { cp_index = get_Java_index_u2(); } diff --git a/src/hotspot/share/interpreter/bytecodeUtils.cpp b/src/hotspot/share/interpreter/bytecodeUtils.cpp index 97b8441365f..1954c839cee 100644 --- a/src/hotspot/share/interpreter/bytecodeUtils.cpp +++ b/src/hotspot/share/interpreter/bytecodeUtils.cpp @@ -968,7 +968,7 @@ int ExceptionMessageBuilder::do_instruction(int bci) { case Bytecodes::_getstatic: case Bytecodes::_getfield: { // Find out the type of the field accessed. - int cp_index = Bytes::get_native_u2(code_base + pos) DEBUG_ONLY(+ ConstantPool::CPCACHE_INDEX_TAG); + int cp_index = Bytes::get_native_u2(code_base + pos); ConstantPool* cp = _method->constants(); int name_and_type_index = cp->name_and_type_ref_index_at(cp_index, code); int type_index = cp->signature_ref_index_at(name_and_type_index); @@ -982,7 +982,7 @@ int ExceptionMessageBuilder::do_instruction(int bci) { case Bytecodes::_putstatic: case Bytecodes::_putfield: { - int cp_index = Bytes::get_native_u2(code_base + pos) DEBUG_ONLY(+ ConstantPool::CPCACHE_INDEX_TAG); + int cp_index = Bytes::get_native_u2(code_base + pos); ConstantPool* cp = _method->constants(); int name_and_type_index = cp->name_and_type_ref_index_at(cp_index, code); int type_index = cp->signature_ref_index_at(name_and_type_index); @@ -1132,7 +1132,7 @@ int ExceptionMessageBuilder::get_NPE_null_slot(int bci) { case Bytecodes::_dastore: return 3; case Bytecodes::_putfield: { - int cp_index = Bytes::get_native_u2(code_base + pos) DEBUG_ONLY(+ ConstantPool::CPCACHE_INDEX_TAG); + int cp_index = Bytes::get_native_u2(code_base + pos); ConstantPool* cp = _method->constants(); int name_and_type_index = cp->name_and_type_ref_index_at(cp_index, code); int type_index = cp->signature_ref_index_at(name_and_type_index); @@ -1326,7 +1326,7 @@ bool ExceptionMessageBuilder::print_NPE_cause0(outputStream* os, int bci, int sl } case Bytecodes::_getstatic: { - int cp_index = Bytes::get_native_u2(code_base + pos) + ConstantPool::CPCACHE_INDEX_TAG; + int cp_index = Bytes::get_native_u2(code_base + pos); print_field_and_class(os, _method, cp_index, code); return true; } @@ -1337,7 +1337,7 @@ bool ExceptionMessageBuilder::print_NPE_cause0(outputStream* os, int bci, int sl if (print_NPE_cause0(os, source_bci, 0, max_detail - 1, inner_expr)) { os->print("."); } - int cp_index = Bytes::get_native_u2(code_base + pos) + ConstantPool::CPCACHE_INDEX_TAG; + int cp_index = Bytes::get_native_u2(code_base + pos); os->print("%s", get_field_name(_method, cp_index, code)); return true; } @@ -1414,7 +1414,7 @@ void ExceptionMessageBuilder::print_NPE_failed_action(outputStream *os, int bci) case Bytecodes::_monitorexit: os->print("Cannot exit synchronized block"); break; case Bytecodes::_getfield: { - int cp_index = Bytes::get_native_u2(code_base + pos) DEBUG_ONLY(+ ConstantPool::CPCACHE_INDEX_TAG); + int cp_index = Bytes::get_native_u2(code_base + pos); ConstantPool* cp = _method->constants(); int name_and_type_index = cp->name_and_type_ref_index_at(cp_index, code); int name_index = cp->name_ref_index_at(name_and_type_index); @@ -1422,7 +1422,7 @@ void ExceptionMessageBuilder::print_NPE_failed_action(outputStream *os, int bci) os->print("Cannot read field \"%s\"", name->as_C_string()); } break; case Bytecodes::_putfield: { - int cp_index = Bytes::get_native_u2(code_base + pos) DEBUG_ONLY(+ ConstantPool::CPCACHE_INDEX_TAG); + int cp_index = Bytes::get_native_u2(code_base + pos); os->print("Cannot assign field \"%s\"", get_field_name(_method, cp_index, code)); } break; case Bytecodes::_invokevirtual: diff --git a/src/hotspot/share/interpreter/bytecodes.hpp b/src/hotspot/share/interpreter/bytecodes.hpp index 5bd2e5663c8..629cca706ae 100644 --- a/src/hotspot/share/interpreter/bytecodes.hpp +++ b/src/hotspot/share/interpreter/bytecodes.hpp @@ -419,6 +419,7 @@ class Bytecodes: AllStatic { || code == _fconst_0 || code == _dconst_0); } static bool is_return (Code code) { return (_ireturn <= code && code <= _return); } static bool is_invoke (Code code) { return (_invokevirtual <= code && code <= _invokedynamic); } + static bool is_field_code (Code code) { return (_getstatic <= java_code(code) && java_code(code) <= _putfield); } static bool has_receiver (Code code) { assert(is_invoke(code), ""); return code == _invokevirtual || code == _invokespecial || code == _invokeinterface; } diff --git a/src/hotspot/share/interpreter/interpreterRuntime.cpp b/src/hotspot/share/interpreter/interpreterRuntime.cpp index ddb6ca32108..33590308976 100644 --- a/src/hotspot/share/interpreter/interpreterRuntime.cpp +++ b/src/hotspot/share/interpreter/interpreterRuntime.cpp @@ -43,7 +43,7 @@ #include "memory/oopFactory.hpp" #include "memory/resourceArea.hpp" #include "memory/universe.hpp" -#include "oops/constantPool.hpp" +#include "oops/constantPool.inline.hpp" #include "oops/cpCache.inline.hpp" #include "oops/instanceKlass.inline.hpp" #include "oops/klass.inline.hpp" @@ -664,16 +664,17 @@ void InterpreterRuntime::resolve_get_put(JavaThread* current, Bytecodes::Code by bytecode == Bytecodes::_putstatic); bool is_static = (bytecode == Bytecodes::_getstatic || bytecode == Bytecodes::_putstatic); + int field_index = last_frame.get_index_u2(bytecode); { JvmtiHideSingleStepping jhss(current); JavaThread* THREAD = current; // For exception macros. - LinkResolver::resolve_field_access(info, pool, last_frame.get_index_u2_cpcache(bytecode), + LinkResolver::resolve_field_access(info, pool, field_index, m, bytecode, CHECK); } // end JvmtiHideSingleStepping // check if link resolution caused cpCache to be updated - ConstantPoolCacheEntry* cp_cache_entry = last_frame.cache_entry(); - if (cp_cache_entry->is_resolved(bytecode)) return; + if (pool->resolved_field_entry_at(field_index)->is_resolved(bytecode)) return; + // compute auxiliary field attributes TosState state = as_TosState(info.field_type()); @@ -713,16 +714,9 @@ void InterpreterRuntime::resolve_get_put(JavaThread* current, Bytecodes::Code by } } - cp_cache_entry->set_field( - get_code, - put_code, - info.field_holder(), - info.index(), - info.offset(), - state, - info.access_flags().is_final(), - info.access_flags().is_volatile() - ); + ResolvedFieldEntry* entry = pool->resolved_field_entry_at(field_index); + entry->set_flags(info.access_flags().is_final(), info.access_flags().is_volatile()); + entry->fill_in(info.field_holder(), info.offset(), (u2)info.index(), (u1)state, (u1)get_code, (u1)put_code); } @@ -1165,12 +1159,12 @@ JRT_LEAF(void, InterpreterRuntime::at_unwind(JavaThread* current)) JRT_END JRT_ENTRY(void, InterpreterRuntime::post_field_access(JavaThread* current, oopDesc* obj, - ConstantPoolCacheEntry *cp_entry)) + ResolvedFieldEntry *entry)) // check the access_flags for the field in the klass - InstanceKlass* ik = InstanceKlass::cast(cp_entry->f1_as_klass()); - int index = cp_entry->field_index(); + InstanceKlass* ik = entry->field_holder(); + int index = entry->field_index(); if (!ik->field_status(index).is_access_watched()) return; bool is_static = (obj == nullptr); @@ -1181,26 +1175,25 @@ JRT_ENTRY(void, InterpreterRuntime::post_field_access(JavaThread* current, oopDe // non-static field accessors have an object, but we need a handle h_obj = Handle(current, obj); } - InstanceKlass* cp_entry_f1 = InstanceKlass::cast(cp_entry->f1_as_klass()); - jfieldID fid = jfieldIDWorkaround::to_jfieldID(cp_entry_f1, cp_entry->f2_as_index(), is_static); + InstanceKlass* field_holder = entry->field_holder(); // HERE + jfieldID fid = jfieldIDWorkaround::to_jfieldID(field_holder, entry->field_offset(), is_static); LastFrameAccessor last_frame(current); - JvmtiExport::post_field_access(current, last_frame.method(), last_frame.bcp(), cp_entry_f1, h_obj, fid); + JvmtiExport::post_field_access(current, last_frame.method(), last_frame.bcp(), field_holder, h_obj, fid); JRT_END JRT_ENTRY(void, InterpreterRuntime::post_field_modification(JavaThread* current, oopDesc* obj, - ConstantPoolCacheEntry *cp_entry, jvalue *value)) + ResolvedFieldEntry *entry, jvalue *value)) - Klass* k = cp_entry->f1_as_klass(); + InstanceKlass* ik = entry->field_holder(); // check the access_flags for the field in the klass - InstanceKlass* ik = InstanceKlass::cast(k); - int index = cp_entry->field_index(); + int index = entry->field_index(); // bail out if field modifications are not watched if (!ik->field_status(index).is_modification_watched()) return; char sig_type = '\0'; - switch(cp_entry->flag_state()) { + switch((TosState)entry->tos_state()) { case btos: sig_type = JVM_SIGNATURE_BYTE; break; case ztos: sig_type = JVM_SIGNATURE_BOOLEAN; break; case ctos: sig_type = JVM_SIGNATURE_CHAR; break; @@ -1215,7 +1208,7 @@ JRT_ENTRY(void, InterpreterRuntime::post_field_modification(JavaThread* current, bool is_static = (obj == nullptr); HandleMark hm(current); - jfieldID fid = jfieldIDWorkaround::to_jfieldID(ik, cp_entry->f2_as_index(), is_static); + jfieldID fid = jfieldIDWorkaround::to_jfieldID(ik, entry->field_offset(), is_static); jvalue fvalue; #ifdef _LP64 fvalue = *value; diff --git a/src/hotspot/share/interpreter/interpreterRuntime.hpp b/src/hotspot/share/interpreter/interpreterRuntime.hpp index 97cfcb1eae6..297585d37e8 100644 --- a/src/hotspot/share/interpreter/interpreterRuntime.hpp +++ b/src/hotspot/share/interpreter/interpreterRuntime.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2023, 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 @@ -120,9 +120,9 @@ class InterpreterRuntime: AllStatic { // Debugger support static void post_field_access(JavaThread* current, oopDesc* obj, - ConstantPoolCacheEntry *cp_entry); + ResolvedFieldEntry* entry); static void post_field_modification(JavaThread* current, oopDesc* obj, - ConstantPoolCacheEntry *cp_entry, jvalue *value); + ResolvedFieldEntry* entry, jvalue *value); static void post_method_entry(JavaThread* current); static void post_method_exit (JavaThread* current); static int interpreter_contains(address pc); diff --git a/src/hotspot/share/interpreter/rewriter.cpp b/src/hotspot/share/interpreter/rewriter.cpp index 95b5855ea62..82fa52361c2 100644 --- a/src/hotspot/share/interpreter/rewriter.cpp +++ b/src/hotspot/share/interpreter/rewriter.cpp @@ -32,6 +32,7 @@ #include "memory/metadataFactory.hpp" #include "memory/resourceArea.hpp" #include "oops/generateOopMap.hpp" +#include "oops/resolvedFieldEntry.hpp" #include "oops/resolvedIndyEntry.hpp" #include "prims/methodHandles.hpp" #include "runtime/arguments.hpp" @@ -49,9 +50,13 @@ void Rewriter::compute_index_maps() { for (int i = 0; i < length; i++) { int tag = _pool->tag_at(i).value(); switch (tag) { - case JVM_CONSTANT_InterfaceMethodref: - case JVM_CONSTANT_Fieldref : // fall through - case JVM_CONSTANT_Methodref : // fall through + case JVM_CONSTANT_Fieldref : + _cp_map.at_put(i, _field_entry_index); + _field_entry_index++; + _initialized_field_entries.push(ResolvedFieldEntry((u2)i)); + break; + case JVM_CONSTANT_InterfaceMethodref: // fall through + case JVM_CONSTANT_Methodref : add_cp_cache_entry(i); break; case JVM_CONSTANT_Dynamic: @@ -100,7 +105,7 @@ void Rewriter::make_constant_pool_cache(TRAPS) { ClassLoaderData* loader_data = _pool->pool_holder()->class_loader_data(); ConstantPoolCache* cache = ConstantPoolCache::allocate(loader_data, _cp_cache_map, - _invokedynamic_references_map, _initialized_indy_entries, CHECK); + _invokedynamic_references_map, _initialized_indy_entries, _initialized_field_entries, CHECK); // initialize object cache in constant pool _pool->set_cache(cache); @@ -175,6 +180,19 @@ void Rewriter::rewrite_Object_init(const methodHandle& method, TRAPS) { } +void Rewriter::rewrite_field_reference(address bcp, int offset, bool reverse) { + address p = bcp + offset; + if (!reverse) { + int cp_index = Bytes::get_Java_u2(p); + int field_entry_index = _cp_map.at(cp_index); + Bytes::put_native_u2(p, field_entry_index); + } else { + int field_entry_index = Bytes::get_native_u2(p); + int pool_index = _initialized_field_entries.at(field_entry_index).constant_pool_index(); + Bytes::put_Java_u2(p, pool_index); + } +} + // Rewrite a classfile-order CP index into a native-order CPC index. void Rewriter::rewrite_member_reference(address bcp, int offset, bool reverse) { address p = bcp + offset; @@ -446,6 +464,8 @@ void Rewriter::scan_method(Thread* thread, Method* method, bool reverse, bool* i // fall through case Bytecodes::_getstatic : // fall through case Bytecodes::_getfield : // fall through + rewrite_field_reference(bcp, prefix_length+1, reverse); + break; case Bytecodes::_invokevirtual : // fall through case Bytecodes::_invokestatic : case Bytecodes::_invokeinterface: @@ -561,7 +581,8 @@ Rewriter::Rewriter(InstanceKlass* klass, const constantPoolHandle& cpool, Array< _resolved_references_map(cpool->length() / 2), _invokedynamic_references_map(cpool->length() / 2), _method_handle_invokers(cpool->length()), - _invokedynamic_index(0) + _invokedynamic_index(0), + _field_entry_index(0) { // Rewrite bytecodes - exception here exits. diff --git a/src/hotspot/share/interpreter/rewriter.hpp b/src/hotspot/share/interpreter/rewriter.hpp index d5b4f7c3dc4..ec3bbfd55d0 100644 --- a/src/hotspot/share/interpreter/rewriter.hpp +++ b/src/hotspot/share/interpreter/rewriter.hpp @@ -27,6 +27,7 @@ #include "memory/allocation.hpp" #include "oops/constantPool.hpp" +#include "oops/resolvedFieldEntry.hpp" #include "oops/resolvedIndyEntry.hpp" #include "utilities/growableArray.hpp" @@ -47,10 +48,12 @@ class Rewriter: public StackObj { GrowableArray _method_handle_invokers; int _resolved_reference_limit; int _invokedynamic_index; + int _field_entry_index; // For collecting information about invokedynamic bytecodes before resolution // With this, we can know how many indy calls there are and resolve them later GrowableArray _initialized_indy_entries; + GrowableArray _initialized_field_entries; void init_maps(int length) { _cp_map.trunc_to(0); @@ -163,6 +166,7 @@ class Rewriter: public StackObj { void make_constant_pool_cache(TRAPS); void scan_method(Thread* thread, Method* m, bool reverse, bool* invokespecial_error); void rewrite_Object_init(const methodHandle& m, TRAPS); + void rewrite_field_reference(address bcp, int offset, bool reverse); void rewrite_member_reference(address bcp, int offset, bool reverse); void maybe_rewrite_invokehandle(address opc, int cp_index, int cache_index, bool reverse); void rewrite_invokedynamic(address bcp, int offset, bool reverse); diff --git a/src/hotspot/share/interpreter/templateTable.hpp b/src/hotspot/share/interpreter/templateTable.hpp index e8409b1dc0f..27f7931d2c7 100644 --- a/src/hotspot/share/interpreter/templateTable.hpp +++ b/src/hotspot/share/interpreter/templateTable.hpp @@ -266,7 +266,16 @@ class TemplateTable: AllStatic { Register cache, // output for CP cache Register index, // output for CP index size_t index_size); // one of 1,2,4 + static void resolve_cache_and_index_for_field(int byte_no, + Register cache, + Register index); static void load_invokedynamic_entry(Register method); + static void load_resolved_field_entry(Register obj, + Register cache, + Register tos_state, + Register off, + Register flags, + bool is_static); static void load_invoke_cp_cache_entry(int byte_no, Register method, Register itable_index, diff --git a/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp b/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp index 5e95fc1d457..356bb7c940b 100644 --- a/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp +++ b/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp @@ -45,6 +45,7 @@ #include "oops/objArrayKlass.hpp" #include "oops/objArrayOop.inline.hpp" #include "oops/oop.inline.hpp" +#include "oops/resolvedFieldEntry.hpp" #include "oops/resolvedIndyEntry.hpp" #include "oops/typeArrayOop.inline.hpp" #include "prims/jvmtiExport.hpp" @@ -406,7 +407,7 @@ JRT_END target = obj; \ } \ CALL_VM(InterpreterRuntime::post_field_access(THREAD, \ - target, cache), \ + target, entry), \ handle_exception); \ } \ } \ @@ -426,7 +427,7 @@ JRT_END target = obj; \ } \ CALL_VM(InterpreterRuntime::post_field_modification(THREAD, \ - target, cache, \ + target, entry, \ (jvalue*)STACK_SLOT(-1)), \ handle_exception); \ } \ @@ -1722,8 +1723,8 @@ void BytecodeInterpreter::run(interpreterState istate) { CASE(_getstatic): { u2 index; - ConstantPoolCacheEntry* cache; index = Bytes::get_native_u2(pc+1); + ResolvedFieldEntry* entry = cp->resolved_field_entry_at(index); // QQQ Need to make this as inlined as possible. Probably need to // split all the bytecode cases out so c++ compiler has a chance @@ -1736,26 +1737,25 @@ void BytecodeInterpreter::run(interpreterState istate) { code = Bytecodes::_getfield; } - cache = cp->entry_at(index); - if (!cache->is_resolved(code)) { + if (!entry->is_resolved(code)) { CALL_VM(InterpreterRuntime::resolve_from_cache(THREAD, code), handle_exception); - cache = cp->entry_at(index); + entry = cp->resolved_field_entry_at(index); } oop obj; if ((Bytecodes::Code)opcode == Bytecodes::_getstatic) { - Klass* k = cache->f1_as_klass(); + Klass* k = entry->field_holder(); obj = k->java_mirror(); MORE_STACK(1); // Assume single slot push } else { obj = STACK_OBJECT(-1); CHECK_NULL(obj); // Check if we can rewrite non-volatile _getfield to one of the _fast_Xgetfield. - if (REWRITE_BYTECODES && !cache->is_volatile() && + if (REWRITE_BYTECODES && !entry->is_volatile() && ((Bytecodes::Code)opcode != Bytecodes::_nofast_getfield)) { // Rewrite current BC to _fast_Xgetfield. - REWRITE_AT_PC(fast_get_type(cache->flag_state())); + REWRITE_AT_PC(fast_get_type((TosState)(entry->tos_state()))); } } @@ -1764,9 +1764,9 @@ void BytecodeInterpreter::run(interpreterState istate) { // // Now store the result on the stack // - TosState tos_type = cache->flag_state(); - int field_offset = cache->f2_as_index(); - if (cache->is_volatile()) { + TosState tos_type = (TosState)(entry->tos_state()); + int field_offset = entry->field_offset(); + if (entry->is_volatile()) { if (support_IRIW_for_not_multiple_copy_atomic_cpu) { OrderAccess::fence(); } @@ -1842,14 +1842,14 @@ void BytecodeInterpreter::run(interpreterState istate) { } UPDATE_PC_AND_CONTINUE(3); - } + } CASE(_putfield): CASE(_nofast_putfield): CASE(_putstatic): { u2 index = Bytes::get_native_u2(pc+1); - ConstantPoolCacheEntry* cache = cp->entry_at(index); + ResolvedFieldEntry* entry = cp->resolved_field_entry_at(index); // Interpreter runtime does not expect "nofast" opcodes, // prepare the vanilla opcode for it. @@ -1858,10 +1858,10 @@ void BytecodeInterpreter::run(interpreterState istate) { code = Bytecodes::_putfield; } - if (!cache->is_resolved(code)) { + if (!entry->is_resolved(code)) { CALL_VM(InterpreterRuntime::resolve_from_cache(THREAD, code), handle_exception); - cache = cp->entry_at(index); + entry = cp->resolved_field_entry_at(index); } // QQQ Need to make this as inlined as possible. Probably need to split all the bytecode cases @@ -1869,14 +1869,14 @@ void BytecodeInterpreter::run(interpreterState istate) { oop obj; int count; - TosState tos_type = cache->flag_state(); + TosState tos_type = (TosState)(entry->tos_state()); count = -1; if (tos_type == ltos || tos_type == dtos) { --count; } if ((Bytecodes::Code)opcode == Bytecodes::_putstatic) { - Klass* k = cache->f1_as_klass(); + Klass* k = entry->field_holder(); obj = k->java_mirror(); } else { --count; @@ -1884,10 +1884,10 @@ void BytecodeInterpreter::run(interpreterState istate) { CHECK_NULL(obj); // Check if we can rewrite non-volatile _putfield to one of the _fast_Xputfield. - if (REWRITE_BYTECODES && !cache->is_volatile() && + if (REWRITE_BYTECODES && !entry->is_volatile() && ((Bytecodes::Code)opcode != Bytecodes::_nofast_putfield)) { // Rewrite current BC to _fast_Xputfield. - REWRITE_AT_PC(fast_put_type(cache->flag_state())); + REWRITE_AT_PC(fast_put_type((TosState)(entry->tos_state()))); } } @@ -1896,8 +1896,8 @@ void BytecodeInterpreter::run(interpreterState istate) { // // Now store the result // - int field_offset = cache->f2_as_index(); - if (cache->is_volatile()) { + int field_offset = entry->field_offset(); + if (entry->is_volatile()) { switch (tos_type) { case ztos: obj->release_byte_field_put(field_offset, (STACK_INT(-1) & 1)); // only store LSB @@ -2585,8 +2585,8 @@ void BytecodeInterpreter::run(interpreterState istate) { CASE(_fast_agetfield): { u2 index = Bytes::get_native_u2(pc+1); - ConstantPoolCacheEntry* cache = cp->entry_at(index); - int field_offset = cache->f2_as_index(); + ResolvedFieldEntry* entry = cp->resolved_field_entry_at(index); + int field_offset = entry->field_offset(); oop obj = STACK_OBJECT(-1); CHECK_NULL(obj); @@ -2600,8 +2600,8 @@ void BytecodeInterpreter::run(interpreterState istate) { CASE(_fast_bgetfield): { u2 index = Bytes::get_native_u2(pc+1); - ConstantPoolCacheEntry* cache = cp->entry_at(index); - int field_offset = cache->f2_as_index(); + ResolvedFieldEntry* entry = cp->resolved_field_entry_at(index); + int field_offset = entry->field_offset(); oop obj = STACK_OBJECT(-1); CHECK_NULL(obj); @@ -2614,8 +2614,8 @@ void BytecodeInterpreter::run(interpreterState istate) { CASE(_fast_cgetfield): { u2 index = Bytes::get_native_u2(pc+1); - ConstantPoolCacheEntry* cache = cp->entry_at(index); - int field_offset = cache->f2_as_index(); + ResolvedFieldEntry* entry = cp->resolved_field_entry_at(index); + int field_offset = entry->field_offset(); oop obj = STACK_OBJECT(-1); CHECK_NULL(obj); @@ -2628,8 +2628,8 @@ void BytecodeInterpreter::run(interpreterState istate) { CASE(_fast_dgetfield): { u2 index = Bytes::get_native_u2(pc+1); - ConstantPoolCacheEntry* cache = cp->entry_at(index); - int field_offset = cache->f2_as_index(); + ResolvedFieldEntry* entry = cp->resolved_field_entry_at(index); + int field_offset = entry->field_offset(); oop obj = STACK_OBJECT(-1); CHECK_NULL(obj); @@ -2643,8 +2643,8 @@ void BytecodeInterpreter::run(interpreterState istate) { CASE(_fast_fgetfield): { u2 index = Bytes::get_native_u2(pc+1); - ConstantPoolCacheEntry* cache = cp->entry_at(index); - int field_offset = cache->f2_as_index(); + ResolvedFieldEntry* entry = cp->resolved_field_entry_at(index); + int field_offset = entry->field_offset(); oop obj = STACK_OBJECT(-1); CHECK_NULL(obj); @@ -2657,8 +2657,8 @@ void BytecodeInterpreter::run(interpreterState istate) { CASE(_fast_igetfield): { u2 index = Bytes::get_native_u2(pc+1); - ConstantPoolCacheEntry* cache = cp->entry_at(index); - int field_offset = cache->f2_as_index(); + ResolvedFieldEntry* entry = cp->resolved_field_entry_at(index); + int field_offset = entry->field_offset(); oop obj = STACK_OBJECT(-1); CHECK_NULL(obj); @@ -2671,8 +2671,8 @@ void BytecodeInterpreter::run(interpreterState istate) { CASE(_fast_lgetfield): { u2 index = Bytes::get_native_u2(pc+1); - ConstantPoolCacheEntry* cache = cp->entry_at(index); - int field_offset = cache->f2_as_index(); + ResolvedFieldEntry* entry = cp->resolved_field_entry_at(index); + int field_offset = entry->field_offset(); oop obj = STACK_OBJECT(-1); CHECK_NULL(obj); @@ -2686,8 +2686,8 @@ void BytecodeInterpreter::run(interpreterState istate) { CASE(_fast_sgetfield): { u2 index = Bytes::get_native_u2(pc+1); - ConstantPoolCacheEntry* cache = cp->entry_at(index); - int field_offset = cache->f2_as_index(); + ResolvedFieldEntry* entry = cp->resolved_field_entry_at(index); + int field_offset = entry->field_offset(); oop obj = STACK_OBJECT(-1); CHECK_NULL(obj); @@ -2700,14 +2700,14 @@ void BytecodeInterpreter::run(interpreterState istate) { CASE(_fast_aputfield): { u2 index = Bytes::get_native_u2(pc+1); - ConstantPoolCacheEntry* cache = cp->entry_at(index); + ResolvedFieldEntry* entry = cp->resolved_field_entry_at(index); oop obj = STACK_OBJECT(-2); CHECK_NULL(obj); MAYBE_POST_FIELD_MODIFICATION(obj); - int field_offset = cache->f2_as_index(); + int field_offset = entry->field_offset(); obj->obj_field_put(field_offset, STACK_OBJECT(-1)); UPDATE_PC_AND_TOS_AND_CONTINUE(3, -2); @@ -2715,14 +2715,14 @@ void BytecodeInterpreter::run(interpreterState istate) { CASE(_fast_bputfield): { u2 index = Bytes::get_native_u2(pc+1); - ConstantPoolCacheEntry* cache = cp->entry_at(index); + ResolvedFieldEntry* entry = cp->resolved_field_entry_at(index); oop obj = STACK_OBJECT(-2); CHECK_NULL(obj); MAYBE_POST_FIELD_MODIFICATION(obj); - int field_offset = cache->f2_as_index(); + int field_offset = entry->field_offset(); obj->byte_field_put(field_offset, STACK_INT(-1)); UPDATE_PC_AND_TOS_AND_CONTINUE(3, -2); @@ -2730,14 +2730,14 @@ void BytecodeInterpreter::run(interpreterState istate) { CASE(_fast_zputfield): { u2 index = Bytes::get_native_u2(pc+1); - ConstantPoolCacheEntry* cache = cp->entry_at(index); + ResolvedFieldEntry* entry = cp->resolved_field_entry_at(index); oop obj = STACK_OBJECT(-2); CHECK_NULL(obj); MAYBE_POST_FIELD_MODIFICATION(obj); - int field_offset = cache->f2_as_index(); + int field_offset = entry->field_offset(); obj->byte_field_put(field_offset, (STACK_INT(-1) & 1)); // only store LSB UPDATE_PC_AND_TOS_AND_CONTINUE(3, -2); @@ -2745,14 +2745,14 @@ void BytecodeInterpreter::run(interpreterState istate) { CASE(_fast_cputfield): { u2 index = Bytes::get_native_u2(pc+1); - ConstantPoolCacheEntry* cache = cp->entry_at(index); + ResolvedFieldEntry* entry = cp->resolved_field_entry_at(index); oop obj = STACK_OBJECT(-2); CHECK_NULL(obj); MAYBE_POST_FIELD_MODIFICATION(obj); - int field_offset = cache->f2_as_index(); + int field_offset = entry->field_offset(); obj->char_field_put(field_offset, STACK_INT(-1)); UPDATE_PC_AND_TOS_AND_CONTINUE(3, -2); @@ -2760,14 +2760,14 @@ void BytecodeInterpreter::run(interpreterState istate) { CASE(_fast_dputfield): { u2 index = Bytes::get_native_u2(pc+1); - ConstantPoolCacheEntry* cache = cp->entry_at(index); + ResolvedFieldEntry* entry = cp->resolved_field_entry_at(index); oop obj = STACK_OBJECT(-3); CHECK_NULL(obj); MAYBE_POST_FIELD_MODIFICATION(obj); - int field_offset = cache->f2_as_index(); + int field_offset = entry->field_offset(); obj->double_field_put(field_offset, STACK_DOUBLE(-1)); UPDATE_PC_AND_TOS_AND_CONTINUE(3, -3); @@ -2775,14 +2775,14 @@ void BytecodeInterpreter::run(interpreterState istate) { CASE(_fast_fputfield): { u2 index = Bytes::get_native_u2(pc+1); - ConstantPoolCacheEntry* cache = cp->entry_at(index); + ResolvedFieldEntry* entry = cp->resolved_field_entry_at(index); oop obj = STACK_OBJECT(-2); CHECK_NULL(obj); MAYBE_POST_FIELD_MODIFICATION(obj); - int field_offset = cache->f2_as_index(); + int field_offset = entry->field_offset(); obj->float_field_put(field_offset, STACK_FLOAT(-1)); UPDATE_PC_AND_TOS_AND_CONTINUE(3, -2); @@ -2790,14 +2790,14 @@ void BytecodeInterpreter::run(interpreterState istate) { CASE(_fast_iputfield): { u2 index = Bytes::get_native_u2(pc+1); - ConstantPoolCacheEntry* cache = cp->entry_at(index); + ResolvedFieldEntry* entry = cp->resolved_field_entry_at(index); oop obj = STACK_OBJECT(-2); CHECK_NULL(obj); MAYBE_POST_FIELD_MODIFICATION(obj); - int field_offset = cache->f2_as_index(); + int field_offset = entry->field_offset(); obj->int_field_put(field_offset, STACK_INT(-1)); UPDATE_PC_AND_TOS_AND_CONTINUE(3, -2); @@ -2805,14 +2805,14 @@ void BytecodeInterpreter::run(interpreterState istate) { CASE(_fast_lputfield): { u2 index = Bytes::get_native_u2(pc+1); - ConstantPoolCacheEntry* cache = cp->entry_at(index); + ResolvedFieldEntry* entry = cp->resolved_field_entry_at(index); oop obj = STACK_OBJECT(-3); CHECK_NULL(obj); MAYBE_POST_FIELD_MODIFICATION(obj); - int field_offset = cache->f2_as_index(); + int field_offset = entry->field_offset(); obj->long_field_put(field_offset, STACK_LONG(-1)); UPDATE_PC_AND_TOS_AND_CONTINUE(3, -3); @@ -2820,14 +2820,14 @@ void BytecodeInterpreter::run(interpreterState istate) { CASE(_fast_sputfield): { u2 index = Bytes::get_native_u2(pc+1); - ConstantPoolCacheEntry* cache = cp->entry_at(index); + ResolvedFieldEntry* entry = cp->resolved_field_entry_at(index); oop obj = STACK_OBJECT(-2); CHECK_NULL(obj); MAYBE_POST_FIELD_MODIFICATION(obj); - int field_offset = cache->f2_as_index(); + int field_offset = entry->field_offset(); obj->short_field_put(field_offset, STACK_INT(-1)); UPDATE_PC_AND_TOS_AND_CONTINUE(3, -2); @@ -2842,8 +2842,8 @@ void BytecodeInterpreter::run(interpreterState istate) { CASE(_fast_aaccess_0): { u2 index = Bytes::get_native_u2(pc+2); - ConstantPoolCacheEntry* cache = cp->entry_at(index); - int field_offset = cache->f2_as_index(); + ResolvedFieldEntry* entry = cp->resolved_field_entry_at(index); + int field_offset = entry->field_offset(); oop obj = LOCALS_OBJECT(0); CHECK_NULL(obj); @@ -2858,8 +2858,8 @@ void BytecodeInterpreter::run(interpreterState istate) { CASE(_fast_iaccess_0): { u2 index = Bytes::get_native_u2(pc+2); - ConstantPoolCacheEntry* cache = cp->entry_at(index); - int field_offset = cache->f2_as_index(); + ResolvedFieldEntry* entry = cp->resolved_field_entry_at(index); + int field_offset = entry->field_offset(); oop obj = LOCALS_OBJECT(0); CHECK_NULL(obj); @@ -2873,8 +2873,8 @@ void BytecodeInterpreter::run(interpreterState istate) { CASE(_fast_faccess_0): { u2 index = Bytes::get_native_u2(pc+2); - ConstantPoolCacheEntry* cache = cp->entry_at(index); - int field_offset = cache->f2_as_index(); + ResolvedFieldEntry* entry = cp->resolved_field_entry_at(index); + int field_offset = entry->field_offset(); oop obj = LOCALS_OBJECT(0); CHECK_NULL(obj); diff --git a/src/hotspot/share/oops/constantPool.cpp b/src/hotspot/share/oops/constantPool.cpp index f697164c630..9840ba5cf66 100644 --- a/src/hotspot/share/oops/constantPool.cpp +++ b/src/hotspot/share/oops/constantPool.cpp @@ -685,8 +685,7 @@ int ConstantPool::to_cp_index(int index, Bytecodes::Code code) { case Bytecodes::_getstatic: case Bytecodes::_putfield: case Bytecodes::_putstatic: - // TODO: handle resolved field entries with new structure - // i = .... + return resolved_field_entry_at(index)->constant_pool_index(); case Bytecodes::_invokeinterface: case Bytecodes::_invokehandle: case Bytecodes::_invokespecial: @@ -737,7 +736,6 @@ u2 ConstantPool::klass_ref_index_at(int index, Bytecodes::Code code) { return uncached_klass_ref_index_at(to_cp_index(index, code)); } - int ConstantPool::remap_instruction_operand_from_cache(int operand) { int cpc_index = operand; DEBUG_ONLY(cpc_index -= CPCACHE_INDEX_TAG); diff --git a/src/hotspot/share/oops/constantPool.hpp b/src/hotspot/share/oops/constantPool.hpp index 9563b364a25..5a92ece4512 100644 --- a/src/hotspot/share/oops/constantPool.hpp +++ b/src/hotspot/share/oops/constantPool.hpp @@ -919,6 +919,10 @@ class ConstantPool : public Metadata { const char* internal_name() const { return "{constant pool}"; } + // ResolvedFieldEntry getters + inline ResolvedFieldEntry* resolved_field_entry_at(int field_index); + inline int resolved_field_entries_length() const; + // ResolvedIndyEntry getters inline ResolvedIndyEntry* resolved_indy_entry_at(int index); inline int resolved_indy_entries_length() const; diff --git a/src/hotspot/share/oops/constantPool.inline.hpp b/src/hotspot/share/oops/constantPool.inline.hpp index f553c385cde..e6e67f0a58b 100644 --- a/src/hotspot/share/oops/constantPool.inline.hpp +++ b/src/hotspot/share/oops/constantPool.inline.hpp @@ -28,6 +28,7 @@ #include "oops/constantPool.hpp" #include "oops/cpCache.inline.hpp" +#include "oops/resolvedFieldEntry.hpp" #include "oops/resolvedIndyEntry.hpp" #include "runtime/atomic.hpp" @@ -42,6 +43,14 @@ inline Klass* ConstantPool::resolved_klass_at(int which) const { // Used by Com return Atomic::load_acquire(adr); } +inline ResolvedFieldEntry* ConstantPool::resolved_field_entry_at(int field_index) { + return cache()->resolved_field_entry_at(field_index); +} + +inline int ConstantPool::resolved_field_entries_length() const { + return cache()->resolved_field_entries_length(); +} + inline u2 ConstantPool::invokedynamic_bootstrap_ref_index_at(int indy_index) const { return cache()->resolved_indy_entry_at(decode_invokedynamic_index(indy_index))->constant_pool_index(); } diff --git a/src/hotspot/share/oops/cpCache.cpp b/src/hotspot/share/oops/cpCache.cpp index fa785389e8c..9a9d147632d 100644 --- a/src/hotspot/share/oops/cpCache.cpp +++ b/src/hotspot/share/oops/cpCache.cpp @@ -46,6 +46,7 @@ #include "oops/cpCache.inline.hpp" #include "oops/objArrayOop.inline.hpp" #include "oops/oop.inline.hpp" +#include "oops/resolvedFieldEntry.hpp" #include "oops/resolvedIndyEntry.hpp" #include "prims/methodHandles.hpp" #include "runtime/arguments.hpp" @@ -640,28 +641,35 @@ void ConstantPoolCacheEntry::verify(outputStream* st) const { // Implementation of ConstantPoolCache +template +static Array* initialize_resolved_entries_array(ClassLoaderData* loader_data, GrowableArray entries, TRAPS) { + Array* resolved_entries; + if (entries.length() != 0) { + resolved_entries = MetadataFactory::new_array(loader_data, entries.length(), CHECK_NULL); + for (int i = 0; i < entries.length(); i++) { + resolved_entries->at_put(i, entries.at(i)); + } + return resolved_entries; + } + return nullptr; +} + ConstantPoolCache* ConstantPoolCache::allocate(ClassLoaderData* loader_data, const intStack& index_map, const intStack& invokedynamic_map, const GrowableArray indy_entries, + const GrowableArray field_entries, TRAPS) { const int length = index_map.length(); int size = ConstantPoolCache::size(length); - // Initialize ResolvedIndyEntry array with available data - Array* resolved_indy_entries; - if (indy_entries.length()) { - resolved_indy_entries = MetadataFactory::new_array(loader_data, indy_entries.length(), CHECK_NULL); - for (int i = 0; i < indy_entries.length(); i++) { - resolved_indy_entries->at_put(i, indy_entries.at(i)); - } - } else { - resolved_indy_entries = nullptr; - } + // Initialize resolved entry arrays with available data + Array* resolved_field_entries = initialize_resolved_entries_array(loader_data, field_entries, CHECK_NULL); + Array* resolved_indy_entries = initialize_resolved_entries_array(loader_data, indy_entries, CHECK_NULL); return new (loader_data, size, MetaspaceObj::ConstantPoolCacheType, THREAD) - ConstantPoolCache(length, index_map, invokedynamic_map, resolved_indy_entries); + ConstantPoolCache(length, index_map, invokedynamic_map, resolved_indy_entries, resolved_field_entries); } void ConstantPoolCache::initialize(const intArray& inverse_index_map, @@ -714,6 +722,11 @@ void ConstantPoolCache::remove_unshareable_info() { resolved_indy_entry_at(i)->remove_unshareable_info(); } } + if (_resolved_field_entries != nullptr) { + for (int i = 0; i < _resolved_field_entries->length(); i++) { + resolved_field_entry_at(i)->remove_unshareable_info(); + } + } } #endif // INCLUDE_CDS @@ -727,8 +740,14 @@ void ConstantPoolCache::deallocate_contents(ClassLoaderData* data) { if (_initial_entries != nullptr) { Arguments::assert_is_dumping_archive(); MetadataFactory::free_array(data, _initial_entries); - if (_resolved_indy_entries) + if (_resolved_indy_entries) { MetadataFactory::free_array(data, _resolved_indy_entries); + _resolved_indy_entries = nullptr; + } + if (_resolved_field_entries) { + MetadataFactory::free_array(data, _resolved_field_entries); + _resolved_field_entries = nullptr; + } _initial_entries = nullptr; } #endif @@ -830,6 +849,9 @@ void ConstantPoolCache::metaspace_pointers_do(MetaspaceClosure* it) { if (_resolved_indy_entries != nullptr) { it->push(&_resolved_indy_entries, MetaspaceClosure::_writable); } + if (_resolved_field_entries != nullptr) { + it->push(&_resolved_field_entries, MetaspaceClosure::_writable); + } } bool ConstantPoolCache::save_and_throw_indy_exc( @@ -924,14 +946,8 @@ void ConstantPoolCache::print_on(outputStream* st) const { st->print_cr("%s", internal_name()); // print constant pool cache entries for (int i = 0; i < length(); i++) entry_at(i)->print(st, i, this); - for (int i = 0; i < resolved_indy_entries_length(); i++) { - ResolvedIndyEntry* indy_entry = resolved_indy_entry_at(i); - indy_entry->print_on(st); - if (indy_entry->has_appendix()) { - st->print(" appendix: "); - constant_pool()->resolved_reference_from_indy(i)->print_on(st); - } - } + print_resolved_field_entries(st); + print_resolved_indy_entries(st); } void ConstantPoolCache::print_value_on(outputStream* st) const { @@ -942,9 +958,20 @@ void ConstantPoolCache::print_value_on(outputStream* st) const { } -void ConstantPoolCache::print_resolved_indy_entries(outputStream* st) const { - for (int i = 0; i < _resolved_indy_entries->length(); i++) { - _resolved_indy_entries->at(i).print_on(st); +void ConstantPoolCache::print_resolved_field_entries(outputStream* st) const { + for (int field_index = 0; field_index < resolved_field_entries_length(); field_index++) { + resolved_field_entry_at(field_index)->print_on(st); + } +} + +void ConstantPoolCache::print_resolved_indy_entries(outputStream* st) const { + for (int indy_index = 0; indy_index < resolved_indy_entries_length(); indy_index++) { + ResolvedIndyEntry* indy_entry = resolved_indy_entry_at(indy_index); + indy_entry->print_on(st); + if (indy_entry->has_appendix()) { + st->print(" appendix: "); + constant_pool()->resolved_reference_from_indy(indy_index)->print_on(st); + } } } diff --git a/src/hotspot/share/oops/cpCache.hpp b/src/hotspot/share/oops/cpCache.hpp index 5c9810fa2c1..5d965ee26b5 100644 --- a/src/hotspot/share/oops/cpCache.hpp +++ b/src/hotspot/share/oops/cpCache.hpp @@ -128,6 +128,7 @@ // source code. The _indices field with the bytecode must be written last. class CallInfo; +class ResolvedFieldEntry; class ResolvedIndyEntry; class ConstantPoolCacheEntry { @@ -406,7 +407,8 @@ class ConstantPoolCache: public MetaspaceObj { // RedefineClasses support uint64_t _gc_epoch; - Array* _resolved_indy_entries; + Array* _resolved_indy_entries; + Array* _resolved_field_entries; CDS_ONLY(Array* _initial_entries;) @@ -417,7 +419,8 @@ class ConstantPoolCache: public MetaspaceObj { ConstantPoolCache(int length, const intStack& inverse_index_map, const intStack& invokedynamic_references_map, - Array* indy_info); + Array* indy_info, + Array* field_entries); // Initialization void initialize(const intArray& inverse_index_map, @@ -427,6 +430,7 @@ class ConstantPoolCache: public MetaspaceObj { const intStack& cp_cache_map, const intStack& invokedynamic_references_map, const GrowableArray indy_entries, + const GrowableArray field_entries, TRAPS); int length() const { return _length; } @@ -442,14 +446,20 @@ class ConstantPoolCache: public MetaspaceObj { Array* reference_map() const { return _reference_map; } void set_reference_map(Array* o) { _reference_map = o; } + Array* resolved_field_entries() { return _resolved_field_entries; } + inline ResolvedFieldEntry* resolved_field_entry_at(int field_index) const; + inline int resolved_field_entries_length() const; + void print_resolved_field_entries(outputStream* st) const; + Array* resolved_indy_entries() { return _resolved_indy_entries; } inline ResolvedIndyEntry* resolved_indy_entry_at(int index) const; inline int resolved_indy_entries_length() const; void print_resolved_indy_entries(outputStream* st) const; // Assembly code support - static ByteSize resolved_references_offset() { return byte_offset_of(ConstantPoolCache, _resolved_references); } - static ByteSize invokedynamic_entries_offset() { return byte_offset_of(ConstantPoolCache, _resolved_indy_entries); } + static ByteSize resolved_references_offset() { return byte_offset_of(ConstantPoolCache, _resolved_references); } + static ByteSize invokedynamic_entries_offset() { return byte_offset_of(ConstantPoolCache, _resolved_indy_entries); } + static ByteSize field_entries_offset() { return byte_offset_of(ConstantPoolCache, _resolved_field_entries); } #if INCLUDE_CDS void remove_unshareable_info(); diff --git a/src/hotspot/share/oops/cpCache.inline.hpp b/src/hotspot/share/oops/cpCache.inline.hpp index 0ac41976f65..177af1d2589 100644 --- a/src/hotspot/share/oops/cpCache.inline.hpp +++ b/src/hotspot/share/oops/cpCache.inline.hpp @@ -28,6 +28,7 @@ #include "oops/cpCache.hpp" #include "oops/oopHandle.inline.hpp" +#include "oops/resolvedFieldEntry.hpp" #include "oops/resolvedIndyEntry.hpp" #include "runtime/atomic.hpp" @@ -88,11 +89,13 @@ inline bool ConstantPoolCacheEntry::indy_resolution_failed() const { inline ConstantPoolCache::ConstantPoolCache(int length, const intStack& inverse_index_map, const intStack& invokedynamic_references_map, - Array* invokedynamic_info) : + Array* invokedynamic_info, + Array* field_entries) : _length(length), _constant_pool(nullptr), _gc_epoch(0), - _resolved_indy_entries(invokedynamic_info) { + _resolved_indy_entries(invokedynamic_info), + _resolved_field_entries(field_entries) { CDS_JAVA_HEAP_ONLY(_archived_references_index = -1;) initialize(inverse_index_map, invokedynamic_references_map); @@ -107,6 +110,14 @@ inline objArrayOop ConstantPoolCache::resolved_references() { return (objArrayOop)obj; } +inline ResolvedFieldEntry* ConstantPoolCache::resolved_field_entry_at(int field_index) const { + return _resolved_field_entries->adr_at(field_index); +} + +inline int ConstantPoolCache::resolved_field_entries_length() const { + return _resolved_field_entries->length(); +} + inline ResolvedIndyEntry* ConstantPoolCache::resolved_indy_entry_at(int index) const { return _resolved_indy_entries->adr_at(index); } diff --git a/src/hotspot/share/oops/generateOopMap.cpp b/src/hotspot/share/oops/generateOopMap.cpp index 2c7f04bd594..b48bd23cc2e 100644 --- a/src/hotspot/share/oops/generateOopMap.cpp +++ b/src/hotspot/share/oops/generateOopMap.cpp @@ -1597,10 +1597,18 @@ void GenerateOopMap::interp1(BytecodeStream *itr) { case Bytecodes::_jsr: do_jsr(itr->dest()); break; case Bytecodes::_jsr_w: do_jsr(itr->dest_w()); break; - case Bytecodes::_getstatic: do_field(true, true, itr->get_index_u2_cpcache(), itr->bci(), itr->code()); break; - case Bytecodes::_putstatic: do_field(false, true, itr->get_index_u2_cpcache(), itr->bci(), itr->code()); break; - case Bytecodes::_getfield: do_field(true, false, itr->get_index_u2_cpcache(), itr->bci(), itr->code()); break; - case Bytecodes::_putfield: do_field(false, false, itr->get_index_u2_cpcache(), itr->bci(), itr->code()); break; + case Bytecodes::_getstatic: + do_field(true, true, itr->get_index_u2(), itr->bci(), itr->code()); + break; + case Bytecodes::_putstatic: + do_field(false, true, itr->get_index_u2(), itr->bci(), itr->code()); + break; + case Bytecodes::_getfield: + do_field(true, false, itr->get_index_u2(), itr->bci(), itr->code()); + break; + case Bytecodes::_putfield: + do_field(false, false, itr->get_index_u2(), itr->bci(), itr->code()); + break; case Bytecodes::_invokevirtual: case Bytecodes::_invokespecial: do_method(false, false, itr->get_index_u2_cpcache(), itr->bci(), itr->code()); break; diff --git a/src/hotspot/share/oops/resolvedFieldEntry.cpp b/src/hotspot/share/oops/resolvedFieldEntry.cpp new file mode 100644 index 00000000000..779f7676293 --- /dev/null +++ b/src/hotspot/share/oops/resolvedFieldEntry.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2023, 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. + * + */ + +#include "precompiled.hpp" +#include "resolvedFieldEntry.hpp" + +void ResolvedFieldEntry::print_on(outputStream* st) const { + st->print_cr("Field Entry:"); + + if (field_holder() != nullptr) { + st->print_cr(" - Holder: " INTPTR_FORMAT " %s", p2i(field_holder()), field_holder()->external_name()); + } else { + st->print_cr("- Holder: null"); + } + st->print_cr(" - Offset: %d", field_offset()); + st->print_cr(" - Field Index: %d", field_index()); + st->print_cr(" - CP Index: %d", constant_pool_index()); + st->print_cr(" - TOS: %s", type2name(as_BasicType((TosState)tos_state()))); + st->print_cr(" - Is Final: %d", is_final()); + st->print_cr(" - Is Volatile: %d", is_volatile()); + st->print_cr(" - Get Bytecode: %s", Bytecodes::name((Bytecodes::Code)get_code())); + st->print_cr(" - Put Bytecode: %s", Bytecodes::name((Bytecodes::Code)put_code())); +} + +void ResolvedFieldEntry::remove_unshareable_info() { + u2 saved_cpool_index = _cpool_index; + memset(this, 0, sizeof(*this)); + _cpool_index = saved_cpool_index; +} diff --git a/src/hotspot/share/oops/resolvedFieldEntry.hpp b/src/hotspot/share/oops/resolvedFieldEntry.hpp new file mode 100644 index 00000000000..8b654b60530 --- /dev/null +++ b/src/hotspot/share/oops/resolvedFieldEntry.hpp @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2023, 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. + * + */ + +#ifndef SHARE_OOPS_RESOLVEDFIELDENTRY_HPP +#define SHARE_OOPS_RESOLVEDFIELDENTRY_HPP + +#include "interpreter/bytecodes.hpp" +#include "oops/instanceKlass.hpp" +#include "runtime/atomic.hpp" +#include "utilities/sizes.hpp" + +// ResolvedFieldEntry contains the resolution information for field related bytecodes like +// like getfield, putfield, getstatic, and putstatic. A member of this class can be initialized +// with the constant pool index associated with the bytecode before any resolution is done, where +// "resolution" refers to populating the getcode and putcode fields and other relevant information. +// The field's type (TOS), offset, holder klass, and index within that class can all be acquired +// together and are used to populate this structure. These entries are contained +// within the ConstantPoolCache and are accessed with indices added to the invokedynamic bytecode after +// rewriting. + +// Field bytecodes start with a constant pool index as their operate, which is then rewritten to +// a "field index", which is an index into the array of ResolvedFieldEntry. + +//class InstanceKlass; +class ResolvedFieldEntry { + friend class VMStructs; + + InstanceKlass* _field_holder; // Field holder klass + int _field_offset; // Field offset in bytes + u2 _field_index; // Index into field information in holder InstanceKlass + u2 _cpool_index; // Constant pool index + u1 _tos_state; // TOS state + u1 _flags; // Flags: [0000|00|is_final|is_volatile] + u1 _get_code, _put_code; // Get and Put bytecodes of the field + +public: + ResolvedFieldEntry(u2 cpi) : + _field_holder(nullptr), + _field_offset(0), + _field_index(0), + _cpool_index(cpi), + _tos_state(0), + _flags(0), + _get_code(0), + _put_code(0) {} + ResolvedFieldEntry() : + ResolvedFieldEntry(0) {} + + // Bit shift to get flags + // Note: Only two flags exists at the moment but more could be added + enum { + is_volatile_shift = 0, + is_final_shift = 1, // unused + }; + + // Getters + InstanceKlass* field_holder() const { return _field_holder; } + int field_offset() const { return _field_offset; } + u2 field_index() const { return _field_index; } + u2 constant_pool_index() const { return _cpool_index; } + u1 tos_state() const { return _tos_state; } + u1 get_code() const { return Atomic::load_acquire(&_get_code); } + u1 put_code() const { return Atomic::load_acquire(&_put_code); } + bool is_final() const { return (_flags & (1 << is_final_shift)) != 0; } + bool is_volatile () const { return (_flags & (1 << is_volatile_shift)) != 0; } + bool is_resolved(Bytecodes::Code code) const { + switch(code) { + case Bytecodes::_getstatic: + case Bytecodes::_getfield: + return (get_code() == code); + case Bytecodes::_putstatic: + case Bytecodes::_putfield: + return (put_code() == code); + default: + ShouldNotReachHere(); + return false; + } + } + + // Printing + void print_on(outputStream* st) const; + + void set_flags(bool is_final, bool is_volatile) { + u1 new_flags = (static_cast(is_final) << static_cast(is_final_shift)) | static_cast(is_volatile); + _flags = new_flags; + } + + inline void set_bytecode(u1* code, u1 new_code) { + #ifdef ASSERT + // Read once. + volatile Bytecodes::Code c = (Bytecodes::Code)*code; + assert(c == 0 || c == new_code || new_code == 0, "update must be consistent"); + #endif + Atomic::release_store(code, new_code); + } + + // Populate the strucutre with resolution information + void fill_in(InstanceKlass* klass, intx offset, int index, int tos_state, u1 b1, u1 b2) { + _field_holder = klass; + _field_offset = offset; + _field_index = index; + _tos_state = tos_state; + + // These must be set after the other fields + set_bytecode(&_get_code, b1); + set_bytecode(&_put_code, b2); + } + + // CDS + void remove_unshareable_info(); + + // Offsets + static ByteSize field_holder_offset() { return byte_offset_of(ResolvedFieldEntry, _field_holder); } + static ByteSize field_offset_offset() { return byte_offset_of(ResolvedFieldEntry, _field_offset); } + static ByteSize field_index_offset() { return byte_offset_of(ResolvedFieldEntry, _field_index); } + static ByteSize get_code_offset() { return byte_offset_of(ResolvedFieldEntry, _get_code); } + static ByteSize put_code_offset() { return byte_offset_of(ResolvedFieldEntry, _put_code); } + static ByteSize type_offset() { return byte_offset_of(ResolvedFieldEntry, _tos_state); } + static ByteSize flags_offset() { return byte_offset_of(ResolvedFieldEntry, _flags); } + +}; + +#endif //SHARE_OOPS_RESOLVEDFIELDENTRY_HPP diff --git a/src/hotspot/share/prims/jvmtiClassFileReconstituter.cpp b/src/hotspot/share/prims/jvmtiClassFileReconstituter.cpp index 193ef07ddca..699c97c7139 100644 --- a/src/hotspot/share/prims/jvmtiClassFileReconstituter.cpp +++ b/src/hotspot/share/prims/jvmtiClassFileReconstituter.cpp @@ -1026,7 +1026,13 @@ void JvmtiClassFileReconstituter::copy_bytecodes(const methodHandle& mh, case Bytecodes::_getstatic : // fall through case Bytecodes::_putstatic : // fall through case Bytecodes::_getfield : // fall through - case Bytecodes::_putfield : // fall through + case Bytecodes::_putfield : { + int field_index = Bytes::get_native_u2(bcp+1); + u2 pool_index = mh->constants()->resolved_field_entry_at(field_index)->constant_pool_index(); + assert(pool_index < mh->constants()->length(), "sanity check"); + Bytes::put_Java_u2((address)(p+1), pool_index); // java byte ordering + break; + } case Bytecodes::_invokevirtual : // fall through case Bytecodes::_invokespecial : // fall through case Bytecodes::_invokestatic : // fall through diff --git a/src/hotspot/share/prims/methodComparator.cpp b/src/hotspot/share/prims/methodComparator.cpp index 478b4911a24..1511182a836 100644 --- a/src/hotspot/share/prims/methodComparator.cpp +++ b/src/hotspot/share/prims/methodComparator.cpp @@ -88,7 +88,18 @@ bool MethodComparator::args_same(Bytecodes::Code const c_old, Bytecodes::Code c case Bytecodes::_getstatic : // fall through case Bytecodes::_putstatic : // fall through case Bytecodes::_getfield : // fall through - case Bytecodes::_putfield : // fall through + case Bytecodes::_putfield : { + int index_old = s_old->get_index_u2(); + int index_new = s_new->get_index_u2(); + // Check if the names of classes, field/method names and signatures at these indexes + // are the same. Indices which are really into constantpool cache (rather than constant + // pool itself) are accepted by the constantpool query routines below. + if ((old_cp->klass_ref_at_noresolve(index_old, c_old) != new_cp->klass_ref_at_noresolve(index_new, c_old)) || + (old_cp->name_ref_at(index_old, c_old) != new_cp->name_ref_at(index_new, c_old)) || + (old_cp->signature_ref_at(index_old, c_old) != new_cp->signature_ref_at(index_new, c_old))) + return false; + break; + } case Bytecodes::_invokevirtual : // fall through case Bytecodes::_invokespecial : // fall through case Bytecodes::_invokestatic : // fall through diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index 6d736c527f0..90c6e91d9c0 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -1892,6 +1892,24 @@ WB_ENTRY(jint, WB_ConstantPoolEncodeIndyIndex(JNIEnv* env, jobject wb, jint inde return ConstantPool::encode_invokedynamic_index(index); WB_END +WB_ENTRY(jint, WB_getFieldEntriesLength(JNIEnv* env, jobject wb, jclass klass)) + InstanceKlass* ik = InstanceKlass::cast(java_lang_Class::as_Klass(JNIHandles::resolve(klass))); + ConstantPool* cp = ik->constants(); + if (cp->cache() == nullptr) { + return -1; + } + return cp->resolved_field_entries_length(); +WB_END + +WB_ENTRY(jint, WB_getFieldCPIndex(JNIEnv* env, jobject wb, jclass klass, jint index)) + InstanceKlass* ik = InstanceKlass::cast(java_lang_Class::as_Klass(JNIHandles::resolve(klass))); + ConstantPool* cp = ik->constants(); + if (cp->cache() == NULL) { + return -1; + } + return cp->resolved_field_entry_at(index)->constant_pool_index(); +WB_END + WB_ENTRY(jint, WB_getIndyInfoLength(JNIEnv* env, jobject wb, jclass klass)) InstanceKlass* ik = InstanceKlass::cast(java_lang_Class::as_Klass(JNIHandles::resolve(klass))); ConstantPool* cp = ik->constants(); @@ -2786,6 +2804,8 @@ static JNINativeMethod methods[] = { CC"(Ljava/lang/Class;I)I", (void*)&WB_ConstantPoolRemapInstructionOperandFromCache}, {CC"encodeConstantPoolIndyIndex0", CC"(I)I", (void*)&WB_ConstantPoolEncodeIndyIndex}, + {CC"getFieldEntriesLength0", CC"(Ljava/lang/Class;)I", (void*)&WB_getFieldEntriesLength}, + {CC"getFieldCPIndex0", CC"(Ljava/lang/Class;I)I", (void*)&WB_getFieldCPIndex}, {CC"getIndyInfoLength0", CC"(Ljava/lang/Class;)I", (void*)&WB_getIndyInfoLength}, {CC"getIndyCPIndex0", CC"(Ljava/lang/Class;I)I", (void*)&WB_getIndyCPIndex}, {CC"printClasses0", CC"(Ljava/lang/String;I)Ljava/lang/String;", (void*)&WB_printClasses}, diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index abeba1e6b40..04f7f2ba4b2 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -83,6 +83,7 @@ #include "oops/objArrayOop.hpp" #include "oops/oop.inline.hpp" #include "oops/oopHandle.hpp" +#include "oops/resolvedFieldEntry.hpp" #include "oops/resolvedIndyEntry.hpp" #include "oops/symbol.hpp" #include "oops/typeArrayKlass.hpp" @@ -223,6 +224,8 @@ nonstatic_field(ConstantPoolCache, _reference_map, Array*) \ nonstatic_field(ConstantPoolCache, _length, int) \ nonstatic_field(ConstantPoolCache, _constant_pool, ConstantPool*) \ + nonstatic_field(ConstantPoolCache, _resolved_field_entries, Array*) \ + nonstatic_field(ResolvedFieldEntry, _cpool_index, u2) \ nonstatic_field(ConstantPoolCache, _resolved_indy_entries, Array*) \ nonstatic_field(ResolvedIndyEntry, _cpool_index, u2) \ volatile_nonstatic_field(InstanceKlass, _array_klasses, ObjArrayKlass*) \ @@ -479,6 +482,8 @@ \ nonstatic_field(Array, _length, int) \ nonstatic_field(Array, _data[0], Klass*) \ + nonstatic_field(Array, _length, int) \ + nonstatic_field(Array, _data[0], ResolvedFieldEntry) \ nonstatic_field(Array, _length, int) \ nonstatic_field(Array, _data[0], ResolvedIndyEntry) \ \ @@ -962,14 +967,15 @@ /* Array */ \ /************/ \ \ - nonstatic_field(Array, _length, int) \ - unchecked_nonstatic_field(Array, _data, sizeof(int)) \ - unchecked_nonstatic_field(Array, _data, sizeof(u1)) \ - unchecked_nonstatic_field(Array, _data, sizeof(u2)) \ - unchecked_nonstatic_field(Array, _data, sizeof(Method*)) \ - unchecked_nonstatic_field(Array, _data, sizeof(Klass*)) \ - unchecked_nonstatic_field(Array, _data, sizeof(ResolvedIndyEntry)) \ - unchecked_nonstatic_field(Array*>, _data, sizeof(Array*)) \ + nonstatic_field(Array, _length, int) \ + unchecked_nonstatic_field(Array, _data, sizeof(int)) \ + unchecked_nonstatic_field(Array, _data, sizeof(u1)) \ + unchecked_nonstatic_field(Array, _data, sizeof(u2)) \ + unchecked_nonstatic_field(Array, _data, sizeof(Method*)) \ + unchecked_nonstatic_field(Array, _data, sizeof(Klass*)) \ + unchecked_nonstatic_field(Array, _data, sizeof(ResolvedFieldEntry)) \ + unchecked_nonstatic_field(Array, _data, sizeof(ResolvedIndyEntry)) \ + unchecked_nonstatic_field(Array*>, _data, sizeof(Array*)) \ \ /*********************************/ \ /* java_lang_Class fields */ \ @@ -1899,6 +1905,7 @@ declare_type(Array, MetaspaceObj) \ declare_type(Array, MetaspaceObj) \ declare_type(Array, MetaspaceObj) \ + declare_type(Array, MetaspaceObj) \ declare_type(Array, MetaspaceObj) \ declare_type(Array*>, MetaspaceObj) \ \ @@ -1917,6 +1924,7 @@ declare_toplevel_type(RuntimeBlob*) \ declare_toplevel_type(CompressedWriteStream*) \ declare_toplevel_type(ConstantPoolCacheEntry) \ + declare_toplevel_type(ResolvedFieldEntry) \ declare_toplevel_type(ResolvedIndyEntry) \ declare_toplevel_type(elapsedTimer) \ declare_toplevel_type(frame) \ diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ConstantPool.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ConstantPool.java index 34f959e29f0..36cb936eca1 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ConstantPool.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ConstantPool.java @@ -263,8 +263,7 @@ public int to_cp_index(int index, int code) { case Bytecodes._getstatic: case Bytecodes._putfield: case Bytecodes._putstatic: - // TODO: handle resolved field entries with new structure - // i = .... + return getCache().getFieldEntryAt(index).getConstantPoolIndex(); case Bytecodes._invokeinterface: case Bytecodes._invokehandle: case Bytecodes._invokespecial: diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ConstantPoolCache.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ConstantPoolCache.java index 5e8379559ac..0b54f71d2d5 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ConstantPoolCache.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ConstantPoolCache.java @@ -55,6 +55,7 @@ private static synchronized void initialize(TypeDataBase db) throws WrongTypeExc intSize = VM.getVM().getObjectHeap().getIntSize(); resolvedReferences = type.getAddressField("_resolved_references"); referenceMap = type.getAddressField("_reference_map"); + resolvedFieldArray = type.getAddressField("_resolved_field_entries"); resolvedIndyArray = type.getAddressField("_resolved_indy_entries"); } @@ -72,6 +73,7 @@ public ConstantPoolCache(Address addr) { private static long intSize; private static AddressField resolvedReferences; private static AddressField referenceMap; + private static AddressField resolvedFieldArray; private static AddressField resolvedIndyArray; public ConstantPool getConstants() { return (ConstantPool) constants.getValue(this); } @@ -91,6 +93,12 @@ public ResolvedIndyEntry getIndyEntryAt(int i) { return array.getAt(i); } + public ResolvedFieldEntry getFieldEntryAt(int i) { + Address addr = resolvedFieldArray.getValue(getAddress()); + ResolvedFieldArray array = new ResolvedFieldArray(addr); + return array.getAt(i); + } + public int getIntAt(int entry, int fld) { long offset = baseOffset + entry * elementSize + fld * intSize; return (int) getAddress().getCIntegerAt(offset, intSize, true ); diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ResolvedFieldArray.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ResolvedFieldArray.java new file mode 100644 index 00000000000..3e606a9fbab --- /dev/null +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ResolvedFieldArray.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + + package sun.jvm.hotspot.oops; + + import sun.jvm.hotspot.debugger.Address; + import sun.jvm.hotspot.runtime.VM; + import sun.jvm.hotspot.types.Type; + import sun.jvm.hotspot.types.TypeDataBase; + import sun.jvm.hotspot.types.WrongTypeException; + import sun.jvm.hotspot.utilities.GenericArray; + import sun.jvm.hotspot.utilities.Observable; + import sun.jvm.hotspot.utilities.Observer; + + public class ResolvedFieldArray extends GenericArray { + static { + VM.registerVMInitializedObserver(new Observer() { + public void update(Observable o, Object data) { + initialize(VM.getVM().getTypeDataBase()); + } + }); + } + + private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { + elemType = db.lookupType("ResolvedFieldEntry"); + + Type type = db.lookupType("Array"); + dataFieldOffset = type.getAddressField("_data").getOffset(); + } + + private static long dataFieldOffset; + protected static Type elemType; + + public ResolvedFieldArray(Address addr) { + super(addr, dataFieldOffset); + } + + public ResolvedFieldEntry getAt(int index) { + if (index < 0 || index >= length()) throw new ArrayIndexOutOfBoundsException(index + " " + length()); + + Type elemType = getElemType(); + + Address data = getAddress().addOffsetTo(dataFieldOffset); + long elemSize = elemType.getSize(); + + return new ResolvedFieldEntry(data.addOffsetTo(index* elemSize)); + } + + public Type getElemType() { + return elemType; + } + } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ResolvedFieldEntry.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ResolvedFieldEntry.java new file mode 100644 index 00000000000..fee97f97f4d --- /dev/null +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ResolvedFieldEntry.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + + package sun.jvm.hotspot.oops; + + import java.util.*; + import sun.jvm.hotspot.debugger.*; + import sun.jvm.hotspot.runtime.*; + import sun.jvm.hotspot.types.*; + import sun.jvm.hotspot.utilities.*; + import sun.jvm.hotspot.utilities.Observable; + import sun.jvm.hotspot.utilities.Observer; + + public class ResolvedFieldEntry extends VMObject { + private static long size; + private static long baseOffset; + private static CIntegerField cpIndex; + + static { + VM.registerVMInitializedObserver(new Observer() { + public void update(Observable o, Object data) { + initialize(VM.getVM().getTypeDataBase()); + } + }); + } + + private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { + Type type = db.lookupType("ResolvedFieldEntry"); + size = type.getSize(); + + cpIndex = type.getCIntegerField("_cpool_index"); + } + + ResolvedFieldEntry(Address addr) { + super(addr); + } + + public int getConstantPoolIndex() { + return this.getAddress().getJShortAt(cpIndex.getOffset()); + } + + public void iterateFields(MetadataVisitor visitor) { } + } diff --git a/test/hotspot/gtest/oops/test_cpCache_output.cpp b/test/hotspot/gtest/oops/test_cpCache_output.cpp index ad5e420cdf4..8d5015e6eeb 100644 --- a/test/hotspot/gtest/oops/test_cpCache_output.cpp +++ b/test/hotspot/gtest/oops/test_cpCache_output.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 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 @@ -61,6 +61,12 @@ TEST_VM(ConstantPoolCache, print_on) { ASSERT_TRUE(strstr(output, "num parameters:") != NULL) << "must have number of parameters"; // field entry test - ASSERT_TRUE(strstr(output, "volatile:") != NULL) << "must have volatile flag"; - ASSERT_TRUE(strstr(output, "field index:") != NULL) << "must have field index"; + ASSERT_TRUE(strstr(output, "Offset:") != NULL) << "must have field offset"; + ASSERT_TRUE(strstr(output, "Field Index:") != NULL) << "must have field index"; + ASSERT_TRUE(strstr(output, "CP Index:") != NULL) << "must have constant pool index"; + ASSERT_TRUE(strstr(output, "TOS:") != NULL) << "must have type"; + ASSERT_TRUE(strstr(output, "Is Final:") != NULL) << "must have final flag"; + ASSERT_TRUE(strstr(output, "Is Volatile:") != NULL) << "must have volatile flag"; + ASSERT_TRUE(strstr(output, "Put Bytecode:") != NULL) << "must have \"put code\""; + ASSERT_TRUE(strstr(output, "Get Bytecode:") != NULL) << "must have \"get code\""; } diff --git a/test/hotspot/jtreg/compiler/jvmci/compilerToVM/ConstantPoolTestsHelper.java b/test/hotspot/jtreg/compiler/jvmci/compilerToVM/ConstantPoolTestsHelper.java index a751c2eee93..b2fb57f0a87 100644 --- a/test/hotspot/jtreg/compiler/jvmci/compilerToVM/ConstantPoolTestsHelper.java +++ b/test/hotspot/jtreg/compiler/jvmci/compilerToVM/ConstantPoolTestsHelper.java @@ -84,6 +84,13 @@ public int getCPCacheIndex(int cpi) { } } } + if (constantPoolSS.getTagAt(cpi).equals(Tag.FIELDREF)) { + for (int field_index = 0; field_index < WB.getFieldEntriesLength(this.klass); field_index++) { + if (WB.getFieldCPIndex(this.klass, field_index) == cpi) { + return field_index; + } + } + } int cacheLength = WB.getConstantPoolCacheLength(this.klass); int indexTag = WB.getConstantPoolCacheIndexTag(); for (int cpci = indexTag; cpci < cacheLength + indexTag; cpci++) { diff --git a/test/hotspot/jtreg/runtime/interpreter/BytecodeTracerTest.java b/test/hotspot/jtreg/runtime/interpreter/BytecodeTracerTest.java index 6e43318e773..289b243f6e1 100644 --- a/test/hotspot/jtreg/runtime/interpreter/BytecodeTracerTest.java +++ b/test/hotspot/jtreg/runtime/interpreter/BytecodeTracerTest.java @@ -172,7 +172,8 @@ public static void main(String args[]) throws Exception { .printClasses("BytecodeTracerTest$Linked", 0xff) .mustMatch("invokedynamic bsm=[0-9]+ [0-9]+ ") .mustMatch("BSM: REF_invokeStatic [0-9]+ "); test("invokedynamic in unlinked class") .printUnlinkedMethods("toString") diff --git a/test/lib/jdk/test/whitebox/WhiteBox.java b/test/lib/jdk/test/whitebox/WhiteBox.java index 5efc2e924dd..ce56ae4b672 100644 --- a/test/lib/jdk/test/whitebox/WhiteBox.java +++ b/test/lib/jdk/test/whitebox/WhiteBox.java @@ -151,6 +151,18 @@ public int encodeConstantPoolIndyIndex(int index) { return encodeConstantPoolIndyIndex0(index); } + private native int getFieldEntriesLength0(Class aClass); + public int getFieldEntriesLength(Class aClass) { + Objects.requireNonNull(aClass); + return getFieldEntriesLength0(aClass); + } + + private native int getFieldCPIndex0(Class aClass, int index); + public int getFieldCPIndex(Class aClass, int index) { + Objects.requireNonNull(aClass); + return getFieldCPIndex0(aClass, index); + } + private native int getIndyInfoLength0(Class aClass); public int getIndyInfoLength(Class aClass) { Objects.requireNonNull(aClass); From 6af0af593446bc33dc94bbf7334c325c4ac0ac0f Mon Sep 17 00:00:00 2001 From: Jim Laskey Date: Mon, 31 Jul 2023 19:11:14 +0000 Subject: [PATCH 09/11] 8310913: Move ReferencedKeyMap to jdk.internal so it may be shared Reviewed-by: naoto, rriggs, mchung, liach --- .../classes/java/lang/invoke/MethodType.java | 131 +---------- .../classes/java/lang/runtime/Carriers.java | 3 +- .../internal/access/JavaLangRefAccess.java | 2 +- .../internal/util}/ReferenceKey.java | 12 +- .../internal/util}/ReferencedKeyMap.java | 156 +++++++++++-- .../jdk/internal/util/ReferencedKeySet.java | 205 ++++++++++++++++++ .../internal/util}/SoftReferenceKey.java | 7 +- .../internal/util}/StrongReferenceKey.java | 5 +- .../internal/util}/WeakReferenceKey.java | 7 +- .../java/lang/runtime/ReferencedKeyTest.java | 109 ---------- .../jdk/internal/util/ReferencedKeyTest.java | 175 +++++++++++++++ 11 files changed, 537 insertions(+), 275 deletions(-) rename src/java.base/share/classes/{java/lang/runtime => jdk/internal/util}/ReferenceKey.java (81%) rename src/java.base/share/classes/{java/lang/runtime => jdk/internal/util}/ReferencedKeyMap.java (63%) create mode 100644 src/java.base/share/classes/jdk/internal/util/ReferencedKeySet.java rename src/java.base/share/classes/{java/lang/runtime => jdk/internal/util}/SoftReferenceKey.java (94%) rename src/java.base/share/classes/{java/lang/runtime => jdk/internal/util}/StrongReferenceKey.java (93%) rename src/java.base/share/classes/{java/lang/runtime => jdk/internal/util}/WeakReferenceKey.java (94%) delete mode 100644 test/jdk/java/lang/runtime/ReferencedKeyTest.java create mode 100644 test/jdk/jdk/internal/util/ReferencedKeyTest.java diff --git a/src/java.base/share/classes/java/lang/invoke/MethodType.java b/src/java.base/share/classes/java/lang/invoke/MethodType.java index 31f7ab862f5..d833e9d17c0 100644 --- a/src/java.base/share/classes/java/lang/invoke/MethodType.java +++ b/src/java.base/share/classes/java/lang/invoke/MethodType.java @@ -33,7 +33,9 @@ import java.lang.ref.WeakReference; import java.util.Arrays; import java.util.Collections; +import java.util.function.Supplier; import java.util.List; +import java.util.Map; import java.util.NoSuchElementException; import java.util.Objects; import java.util.Optional; @@ -42,7 +44,8 @@ import java.util.concurrent.ConcurrentMap; import java.util.stream.Stream; -import jdk.internal.access.SharedSecrets; +import jdk.internal.util.ReferencedKeySet; +import jdk.internal.util.ReferenceKey; import jdk.internal.vm.annotation.Stable; import sun.invoke.util.BytecodeDescriptor; import sun.invoke.util.VerifyType; @@ -227,7 +230,13 @@ private static IndexOutOfBoundsException newIndexOutOfBoundsException(Object num return new IndexOutOfBoundsException(num.toString()); } - static final ConcurrentWeakInternSet internTable = new ConcurrentWeakInternSet<>(); + static final ReferencedKeySet internTable = + ReferencedKeySet.create(false, true, new Supplier<>() { + @Override + public Map, ReferenceKey> get() { + return new ConcurrentHashMap<>(512); + } + }); static final Class[] NO_PTYPES = {}; @@ -405,7 +414,7 @@ private static MethodType makeImpl(Class rtype, Class[] ptypes, boolean tr mt = new MethodType(rtype, ptypes); } mt.form = MethodTypeForm.findForm(mt); - return internTable.add(mt); + return internTable.intern(mt); } private static final @Stable MethodType[] objectOnlyTypes = new MethodType[20]; @@ -883,10 +892,6 @@ public Class[] parameterArray() { * @param x object to compare * @see Object#equals(Object) */ - // This implementation may also return true if x is a WeakEntry containing - // a method type that is equal to this. This is an internal implementation - // detail to allow for faster method type lookups. - // See ConcurrentWeakInternSet.WeakEntry#equals(Object) @Override public boolean equals(Object x) { if (this == x) { @@ -895,10 +900,6 @@ public boolean equals(Object x) { if (x instanceof MethodType mt) { return equals(mt); } - if (x instanceof ConcurrentWeakInternSet.WeakEntry e - && e.get() instanceof MethodType mt) { - return equals(mt); - } return false; } @@ -1390,112 +1391,4 @@ private Object readResolve() { wrapAlt = null; return mt; } - - /** - * Simple implementation of weak concurrent intern set. - * - * @param interned type - */ - private static class ConcurrentWeakInternSet { - - private final ConcurrentMap, WeakEntry> map; - private final ReferenceQueue stale; - - public ConcurrentWeakInternSet() { - this.map = new ConcurrentHashMap<>(512); - this.stale = SharedSecrets.getJavaLangRefAccess().newNativeReferenceQueue(); - } - - /** - * Get the existing interned element. - * This method returns null if no element is interned. - * - * @param elem element to look up - * @return the interned element - */ - public T get(T elem) { - if (elem == null) throw new NullPointerException(); - expungeStaleElements(); - - WeakEntry value = map.get(elem); - if (value != null) { - T res = value.get(); - if (res != null) { - return res; - } - } - return null; - } - - /** - * Interns the element. - * Always returns non-null element, matching the one in the intern set. - * Under the race against another add(), it can return different - * element, if another thread beats us to interning it. - * - * @param elem element to add - * @return element that was actually added - */ - public T add(T elem) { - if (elem == null) throw new NullPointerException(); - - // Playing double race here, and so spinloop is required. - // First race is with two concurrent updaters. - // Second race is with GC purging weak ref under our feet. - // Hopefully, we almost always end up with a single pass. - T interned; - WeakEntry e = new WeakEntry<>(elem, stale); - do { - expungeStaleElements(); - WeakEntry exist = map.putIfAbsent(e, e); - interned = (exist == null) ? elem : exist.get(); - } while (interned == null); - return interned; - } - - private void expungeStaleElements() { - Reference reference; - while ((reference = stale.poll()) != null) { - map.remove(reference); - } - } - - private static class WeakEntry extends WeakReference { - - public final int hashcode; - - public WeakEntry(T key, ReferenceQueue queue) { - super(key, queue); - hashcode = key.hashCode(); - } - - /** - * This implementation returns {@code true} if {@code obj} is another - * {@code WeakEntry} whose referent is equal to this referent, or - * if {@code obj} is equal to the referent of this. This allows - * lookups to be made without wrapping in a {@code WeakEntry}. - * - * @param obj the object to compare - * @return true if {@code obj} is equal to this or the referent of this - * @see MethodType#equals(Object) - * @see Object#equals(Object) - */ - @Override - public boolean equals(Object obj) { - Object mine = get(); - if (obj instanceof WeakEntry we) { - Object that = we.get(); - return (that == null || mine == null) ? (this == obj) : mine.equals(that); - } - return (mine == null) ? (obj == null) : mine.equals(obj); - } - - @Override - public int hashCode() { - return hashcode; - } - - } - } - } diff --git a/src/java.base/share/classes/java/lang/runtime/Carriers.java b/src/java.base/share/classes/java/lang/runtime/Carriers.java index e0ebc998ee5..a74144fcbeb 100644 --- a/src/java.base/share/classes/java/lang/runtime/Carriers.java +++ b/src/java.base/share/classes/java/lang/runtime/Carriers.java @@ -35,6 +35,7 @@ import java.util.concurrent.ConcurrentHashMap; import jdk.internal.misc.Unsafe; +import jdk.internal.util.ReferencedKeyMap; import static java.lang.invoke.MethodType.methodType; @@ -366,7 +367,7 @@ MethodHandle[] createComponents(CarrierShape carrierShape) { * Cache mapping {@link MethodType} to previously defined {@link CarrierElements}. */ private static final Map - methodTypeCache = ReferencedKeyMap.create(ConcurrentHashMap::new); + methodTypeCache = ReferencedKeyMap.create(false, ConcurrentHashMap::new); /** * Permute a raw constructor and component accessor {@link MethodHandle MethodHandles} to diff --git a/src/java.base/share/classes/jdk/internal/access/JavaLangRefAccess.java b/src/java.base/share/classes/jdk/internal/access/JavaLangRefAccess.java index b9b180fc2da..ed9967ec3eb 100644 --- a/src/java.base/share/classes/jdk/internal/access/JavaLangRefAccess.java +++ b/src/java.base/share/classes/jdk/internal/access/JavaLangRefAccess.java @@ -54,7 +54,7 @@ public interface JavaLangRefAccess { /** * Constructs a new NativeReferenceQueue. * - * Invoked by MethodType.ConcurrentWeakInternSet + * Invoked by jdk.internal.util.ReferencedKeyMap */ ReferenceQueue newNativeReferenceQueue(); } diff --git a/src/java.base/share/classes/java/lang/runtime/ReferenceKey.java b/src/java.base/share/classes/jdk/internal/util/ReferenceKey.java similarity index 81% rename from src/java.base/share/classes/java/lang/runtime/ReferenceKey.java rename to src/java.base/share/classes/jdk/internal/util/ReferenceKey.java index 983d81d3a0f..a193794fe70 100644 --- a/src/java.base/share/classes/java/lang/runtime/ReferenceKey.java +++ b/src/java.base/share/classes/jdk/internal/util/ReferenceKey.java @@ -23,12 +23,9 @@ * questions. */ -package java.lang.runtime; +package jdk.internal.util; -import java.lang.ref.ReferenceQueue; -import java.lang.ref.SoftReference; -import java.lang.ref.WeakReference; -import java.util.Objects; +import java.lang.ref.Reference; /** * View/wrapper of keys used by the backing {@link ReferencedKeyMap}. @@ -39,11 +36,8 @@ * @param key type * * @since 21 - * - * Warning: This class is part of PreviewFeature.Feature.STRING_TEMPLATES. - * Do not rely on its availability. */ -sealed interface ReferenceKey permits StrongReferenceKey, WeakReferenceKey, SoftReferenceKey { +public sealed interface ReferenceKey permits StrongReferenceKey, WeakReferenceKey, SoftReferenceKey { /** * {@return the value of the unwrapped key} */ diff --git a/src/java.base/share/classes/java/lang/runtime/ReferencedKeyMap.java b/src/java.base/share/classes/jdk/internal/util/ReferencedKeyMap.java similarity index 63% rename from src/java.base/share/classes/java/lang/runtime/ReferencedKeyMap.java rename to src/java.base/share/classes/jdk/internal/util/ReferencedKeyMap.java index 1ded08c4cba..f102e3c94e1 100644 --- a/src/java.base/share/classes/java/lang/runtime/ReferencedKeyMap.java +++ b/src/java.base/share/classes/jdk/internal/util/ReferencedKeyMap.java @@ -23,7 +23,7 @@ * questions. */ -package java.lang.runtime; +package jdk.internal.util; import java.lang.ref.Reference; import java.lang.ref.ReferenceQueue; @@ -37,9 +37,12 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Supplier; +import java.util.function.UnaryOperator; import java.util.stream.Collectors; import java.util.stream.Stream; +import jdk.internal.access.SharedSecrets; + /** * This class provides management of {@link Map maps} where it is desirable to * remove entries automatically when the key is garbage collected. This is @@ -78,11 +81,8 @@ * @param the type of mapped values * * @since 21 - * - * Warning: This class is part of PreviewFeature.Feature.STRING_TEMPLATES. - * Do not rely on its availability. */ -final class ReferencedKeyMap implements Map { +public final class ReferencedKeyMap implements Map { /** * true if {@link SoftReference} keys are to be used, * {@link WeakReference} otherwise. @@ -95,54 +95,61 @@ final class ReferencedKeyMap implements Map { private final Map, V> map; /** - * {@link ReferenceQueue} for cleaning up {@link WeakReferenceKey EntryKeys}. + * {@link ReferenceQueue} for cleaning up entries. */ private final ReferenceQueue stale; /** * Private constructor. * - * @param isSoft true if {@link SoftReference} keys are to - * be used, {@link WeakReference} otherwise. - * @param map backing map + * @param isSoft true if {@link SoftReference} keys are to + * be used, {@link WeakReference} otherwise. + * @param map backing map + * @param stale {@link ReferenceQueue} for cleaning up entries */ - private ReferencedKeyMap(boolean isSoft, Map, V> map) { + private ReferencedKeyMap(boolean isSoft, Map, V> map, ReferenceQueue stale) { this.isSoft = isSoft; this.map = map; - this.stale = new ReferenceQueue<>(); + this.stale = stale; } /** * Create a new {@link ReferencedKeyMap} map. * - * @param isSoft true if {@link SoftReference} keys are to - * be used, {@link WeakReference} otherwise. - * @param supplier {@link Supplier} of the backing map + * @param isSoft true if {@link SoftReference} keys are to + * be used, {@link WeakReference} otherwise. + * @param supplier {@link Supplier} of the backing map * * @return a new map with {@link Reference} keys * * @param the type of keys maintained by the new map * @param the type of mapped values */ - static ReferencedKeyMap + public static ReferencedKeyMap create(boolean isSoft, Supplier, V>> supplier) { - return new ReferencedKeyMap(isSoft, supplier.get()); + return create(isSoft, false, supplier); } /** - * Create a new {@link ReferencedKeyMap} map using - * {@link WeakReference} keys. + * Create a new {@link ReferencedKeyMap} map. * - * @param supplier {@link Supplier} of the backing map + * @param isSoft true if {@link SoftReference} keys are to + * be used, {@link WeakReference} otherwise. + * @param useNativeQueue true if uses NativeReferenceQueue + * otherwise use {@link ReferenceQueue}. + * @param supplier {@link Supplier} of the backing map * * @return a new map with {@link Reference} keys * * @param the type of keys maintained by the new map * @param the type of mapped values */ - static ReferencedKeyMap - create(Supplier, V>> supplier) { - return new ReferencedKeyMap(false, supplier.get()); + public static ReferencedKeyMap + create(boolean isSoft, boolean useNativeQueue, Supplier, V>> supplier) { + return new ReferencedKeyMap(isSoft, supplier.get(), + useNativeQueue ? SharedSecrets.getJavaLangRefAccess().newNativeReferenceQueue() + : new ReferenceQueue<>() + ); } /** @@ -320,10 +327,9 @@ public String toString() { /** * Removes enqueued weak references from map. */ - @SuppressWarnings("unchecked") public void removeStaleReferences() { while (true) { - WeakReferenceKey key = (WeakReferenceKey)stale.poll(); + Object key = stale.poll(); if (key == null) { break; } @@ -331,4 +337,106 @@ public void removeStaleReferences() { } } + /** + * Puts an entry where the key and the value are the same. Used for + * interning values in a set. + * + * @implNote Requires a {@link ReferencedKeyMap} whose {@code V} type + * is a {@code ReferenceKey}. Otherwise, a {@link ClassCastException} will + * be thrown. + * + * @param setMap {@link ReferencedKeyMap} where interning takes place + * @param key key to add + * + * @param type of key + * + * @return the old key instance if found otherwise the new key instance + * + * @throws ClassCastException if {@code V} is not {@code EntryKey} + */ + static T intern(ReferencedKeyMap> setMap, T key) { + T value = existingKey(setMap, key); + if (value != null) { + return value; + } + return internKey(setMap, key); + } + + /** + * Puts an entry where the key and the value are the same. Used for + * interning values in a set. + * + * @implNote Requires a {@link ReferencedKeyMap} whose {@code V} type + * is a {@code ReferenceKey}. Otherwise, a {@link ClassCastException} will + * be thrown. + * + * @param setMap {@link ReferencedKeyMap} where interning takes place + * @param key key to add + * @param interner operation to apply to key before adding to map + * + * @param type of key + * + * @return the old key instance if found otherwise the new key instance + * + * @throws ClassCastException if {@code V} is not {@code EntryKey} + * + * @implNote This version of intern should not be called during phase1 + * using a lambda. Use an UnaryOperator instance instead. + */ + static T intern(ReferencedKeyMap> setMap, T key, UnaryOperator interner) { + T value = existingKey(setMap, key); + if (value != null) { + return value; + } + key = interner.apply(key); + return internKey(setMap, key); + } + + /** + * Check if the key already exists in the map. + * + * @param setMap {@link ReferencedKeyMap} where interning takes place + * @param key key to test + * + * @param type of key + * + * @return key if found otherwise null + */ + private static T existingKey(ReferencedKeyMap> setMap, T key) { + setMap.removeStaleReferences(); + ReferenceKey entryKey = setMap.get(setMap.lookupKey(key)); + return entryKey != null ? entryKey.get() : null; + } + + /** + * Attempt to add key to map. + * + * @param setMap {@link ReferencedKeyMap} where interning takes place + * @param key key to add + * + * @param type of key + * + * @return the old key instance if found otherwise the new key instance + */ + private static T internKey(ReferencedKeyMap> setMap, T key) { + ReferenceKey entryKey = setMap.entryKey(key); + T interned; + do { + setMap.removeStaleReferences(); + ReferenceKey existing = setMap.map.putIfAbsent(entryKey, entryKey); + if (existing == null) { + return key; + } else { + // If {@code putIfAbsent} returns non-null then was actually a + // {@code replace} and older key was used. In that case the new + // key was not used and the reference marked stale. + interned = existing.get(); + if (interned != null) { + entryKey.unused(); + } + } + } while (interned == null); + return interned; + } + } diff --git a/src/java.base/share/classes/jdk/internal/util/ReferencedKeySet.java b/src/java.base/share/classes/jdk/internal/util/ReferencedKeySet.java new file mode 100644 index 00000000000..807eea87dfe --- /dev/null +++ b/src/java.base/share/classes/jdk/internal/util/ReferencedKeySet.java @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.util; + +import java.lang.ref.Reference; +import java.lang.ref.ReferenceQueue; +import java.lang.ref.SoftReference; +import java.lang.ref.WeakReference; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Supplier; +import java.util.function.UnaryOperator; + +/** + * This class provides management of {@link Set set} where it is desirable to + * remove elements automatically when the element is garbage collected. This is + * accomplished by using a backing map where the keys and values are either a + * {@link WeakReference} or a {@link SoftReference}. + *

+ * To create a {@link ReferencedKeySet} the user must provide a {@link Supplier} + * of the backing map and whether {@link WeakReference} or + * {@link SoftReference} is to be used. + * {@snippet : + * Set set; + * + * set = ReferencedKeySet.create(false, HashMap::new); + * set.add(30_000_000L); + * set.add(30_000_001L); + * set.add(30_000_002L); + * set.add(30_000_003L); + * set.add(30_000_004L); + * + * set = ReferencedKeySet.create(true, ConcurrentHashMap::new); + * set.add(40_000_000L); + * set.add(40_000_001L); + * set.add(40_000_002L); + * set.add(40_000_003L); + * set.add(40_000_004L); + * } + * + * @implNote Care must be given that the backing map does replacement by + * replacing the value in the map entry instead of deleting the old entry and + * adding a new entry, otherwise replaced entries may end up with a strongly + * referenced key. {@link HashMap} and {@link ConcurrentHashMap} are known + * to be safe. + * + * @param the type of elements maintained by this set + */ +public final class ReferencedKeySet extends AbstractSet { + /** + * Backing {@link ReferencedKeySet} map. + */ + final ReferencedKeyMap> map; + + /** + * Private constructor. + * + * @param map backing map + */ + private ReferencedKeySet(ReferencedKeyMap> map) { + this.map = map; + } + + /** + * Create a new {@link ReferencedKeySet} elements. + * + * @param isSoft true if {@link SoftReference} elements are to + * be used, {@link WeakReference} otherwise. + * @param supplier {@link Supplier} of the backing map + * + * @return a new set with {@link Reference} elements + * + * @param the type of elements maintained by this set + */ + public static ReferencedKeySet + create(boolean isSoft, Supplier, ReferenceKey>> supplier) { + return create(isSoft, false, supplier); + } + + /** + * Create a new {@link ReferencedKeySet} elements. + * + * @param isSoft true if {@link SoftReference} elements are to + * be used, {@link WeakReference} otherwise. + * @param useNativeQueue true if uses NativeReferenceQueue + * otherwise use {@link ReferenceQueue}. + * @param supplier {@link Supplier} of the backing map + * + * @return a new set with {@link Reference} elements + * + * @param the type of elements maintained by this set + */ + public static ReferencedKeySet + create(boolean isSoft, boolean useNativeQueue, Supplier, ReferenceKey>> supplier) { + return new ReferencedKeySet<>(ReferencedKeyMap.create(isSoft, useNativeQueue, supplier)); + } + + /** + * Removes enqueued weak references from set. + */ + public void removeStaleReferences() { + map.removeStaleReferences(); + } + + @Override + public Iterator iterator() { + return map.keySet().iterator(); + } + + @Override + public int size() { + return map.size(); + } + + @Override + public boolean isEmpty() { + return map.isEmpty(); + } + + @Override + @SuppressWarnings("unchecked") + public boolean contains(Object o) { + return map.containsKey((T)o); + } + + @Override + public boolean add(T e) { + return intern(e) == null; + } + + @Override + public boolean remove(Object o) { + return map.remove(o) != null; + } + + @Override + public void clear() { + map.clear(); + } + + /** + * Gets an existing element from the set, returning null if not present or + * the old element if previously added. + * + * @param e element to get + * + * @return the old element if present, otherwise, null + */ + public T get(T e) { + ReferenceKey key = map.get(e); + + return key == null ? null : key.get(); + } + + /** + * Intern an element to the set, returning the element if newly added or the + * old element if previously added. + * + * @param e element to add + * + * @return the old element if present, otherwise, the new element + */ + public T intern(T e) { + return ReferencedKeyMap.intern(map, e); + } + + /** + * Intern an element to the set, returning the element if newly added or the + * old element if previously added. + * + * @param e element to add + * @param interner operation to apply to key before adding to set + * + * @return the old element if present, otherwise, the new element + * + * @implNote This version of intern should not be called during phase1 + * using a lambda. Use an UnaryOperator instance instead. + */ + public T intern(T e, UnaryOperator interner) { + return ReferencedKeyMap.intern(map, e, interner); + } +} diff --git a/src/java.base/share/classes/java/lang/runtime/SoftReferenceKey.java b/src/java.base/share/classes/jdk/internal/util/SoftReferenceKey.java similarity index 94% rename from src/java.base/share/classes/java/lang/runtime/SoftReferenceKey.java rename to src/java.base/share/classes/jdk/internal/util/SoftReferenceKey.java index 3bb524e13dd..f7e94e79f0b 100644 --- a/src/java.base/share/classes/java/lang/runtime/SoftReferenceKey.java +++ b/src/java.base/share/classes/jdk/internal/util/SoftReferenceKey.java @@ -23,7 +23,7 @@ * questions. */ -package java.lang.runtime; +package jdk.internal.util; import java.lang.ref.ReferenceQueue; import java.lang.ref.SoftReference; @@ -35,9 +35,6 @@ * @param key type * * @since 21 - * - * Warning: This class is part of PreviewFeature.Feature.STRING_TEMPLATES. - * Do not rely on its availability. */ final class SoftReferenceKey extends SoftReference implements ReferenceKey { /** @@ -76,6 +73,8 @@ public boolean equals(Object obj) { if (obj instanceof ReferenceKey key) { obj = key.get(); } + // Note: refersTo is insufficient since keys require equivalence. + // refersTo would also require a cast to type T. return Objects.equals(get(), obj); } diff --git a/src/java.base/share/classes/java/lang/runtime/StrongReferenceKey.java b/src/java.base/share/classes/jdk/internal/util/StrongReferenceKey.java similarity index 93% rename from src/java.base/share/classes/java/lang/runtime/StrongReferenceKey.java rename to src/java.base/share/classes/jdk/internal/util/StrongReferenceKey.java index 3665cad96cc..e3264cd0dca 100644 --- a/src/java.base/share/classes/java/lang/runtime/StrongReferenceKey.java +++ b/src/java.base/share/classes/jdk/internal/util/StrongReferenceKey.java @@ -23,7 +23,7 @@ * questions. */ -package java.lang.runtime; +package jdk.internal.util; import java.util.Objects; @@ -34,9 +34,6 @@ * @param key type * * @since 21 - * - * Warning: This class is part of PreviewFeature.Feature.STRING_TEMPLATES. - * Do not rely on its availability. */ final class StrongReferenceKey implements ReferenceKey { T key; diff --git a/src/java.base/share/classes/java/lang/runtime/WeakReferenceKey.java b/src/java.base/share/classes/jdk/internal/util/WeakReferenceKey.java similarity index 94% rename from src/java.base/share/classes/java/lang/runtime/WeakReferenceKey.java rename to src/java.base/share/classes/jdk/internal/util/WeakReferenceKey.java index 5d18c2e45a0..3fe6d6026d7 100644 --- a/src/java.base/share/classes/java/lang/runtime/WeakReferenceKey.java +++ b/src/java.base/share/classes/jdk/internal/util/WeakReferenceKey.java @@ -23,7 +23,7 @@ * questions. */ -package java.lang.runtime; +package jdk.internal.util; import java.lang.ref.ReferenceQueue; import java.lang.ref.WeakReference; @@ -35,9 +35,6 @@ * @param key type * * @since 21 - * - * Warning: This class is part of PreviewFeature.Feature.STRING_TEMPLATES. - * Do not rely on its availability. */ final class WeakReferenceKey extends WeakReference implements ReferenceKey { /** @@ -76,6 +73,8 @@ public boolean equals(Object obj) { if (obj instanceof ReferenceKey key) { obj = key.get(); } + // Note: refersTo is insufficient since keys require equivalence. + // refersTo would also require a cast to type T. return Objects.equals(get(), obj); } diff --git a/test/jdk/java/lang/runtime/ReferencedKeyTest.java b/test/jdk/java/lang/runtime/ReferencedKeyTest.java deleted file mode 100644 index 9234cffb98a..00000000000 --- a/test/jdk/java/lang/runtime/ReferencedKeyTest.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (c) 2023, 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 - * @summary Test features provided by the ReferencedKeyMap class. - * @modules java.base/java.lang.runtime - * @enablePreview - * @compile --patch-module java.base=${test.src} ReferencedKeyTest.java - * @run main/othervm --patch-module java.base=${test.class.path} java.lang.runtime.ReferencedKeyTest - */ - -package java.lang.runtime; - -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.function.Supplier; - -public class ReferencedKeyTest { - static long BASE_KEY = 10_000_000L; - - public static void main(String[] args) throws Throwable { - mapTest(false, HashMap::new); - mapTest(true, HashMap::new); - mapTest(false, ConcurrentHashMap::new); - mapTest(true, ConcurrentHashMap::new); - } - - static void assertTrue(boolean test, String message) { - if (!test) { - throw new RuntimeException(message); - } - } - - static void mapTest(boolean isSoft, Supplier, String>> supplier) { - Map map = ReferencedKeyMap.create(isSoft, supplier); - populate(map); - collect(); - // assertTrue(map.isEmpty() || isSoft, "Weak not collecting"); - populate(map); - methods(map); - } - - static void methods(Map map) { - assertTrue(map.size() == 26, "missing key"); - assertTrue(map.containsKey(BASE_KEY + 'a' -'a'), "missing key"); - assertTrue(map.get(BASE_KEY + 'b' -'a').equals("b"), "wrong key"); - assertTrue(map.containsValue("c"), "missing value"); - map.remove(BASE_KEY + 'd' -'a'); - assertTrue(map.get(BASE_KEY + 'd' -'a') == null, "not removed"); - map.putAll(Map.of(1L, "A", 2L, "B")); - assertTrue(map.get(2L).equals("B"), "collection not added"); - assertTrue(map.keySet().contains(1L), "key missing"); - assertTrue(map.values().contains("A"), "key missing"); - assertTrue(map.entrySet().contains(Map.entry(1L, "A")), "key missing"); - map.putIfAbsent(3L, "C"); - assertTrue(map.get(3L).equals("C"), "key missing"); - map.putIfAbsent(2L, "D"); - assertTrue(map.get(2L).equals("B"), "key replaced"); - map.remove(3L); - assertTrue(map.get(3L) == null, "key not removed"); - map.replace(2L, "D"); - assertTrue(map.get(2L).equals("D"), "key not replaced"); - map.replace(2L, "B", "E"); - assertTrue(map.get(2L).equals("D"), "key replaced"); - } - - static void collect() { - System.gc(); - sleep(); - } - - static void sleep() { - try { - Thread.sleep(100L); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - } - - static void populate(Map map) { - for (int i = 0; i < 26; i++) { - Long key = BASE_KEY + i; - String value = String.valueOf((char) ('a' + i)); - map.put(key, value); - } - } -} diff --git a/test/jdk/jdk/internal/util/ReferencedKeyTest.java b/test/jdk/jdk/internal/util/ReferencedKeyTest.java new file mode 100644 index 00000000000..c5edaedd2e2 --- /dev/null +++ b/test/jdk/jdk/internal/util/ReferencedKeyTest.java @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2023, 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 + * @bug 8285932 8310913 + * @summary Test features provided by the ReferencedKeyMap/ReferencedKeySet classes. + * @modules java.base/jdk.internal.util + * @compile --patch-module java.base=${test.src} ReferencedKeyTest.java + * @run main/othervm --patch-module java.base=${test.class.path} jdk.internal.util.ReferencedKeyTest + */ + +package jdk.internal.util; + +import java.lang.ref.PhantomReference; +import java.lang.ref.Reference; +import java.lang.ref.ReferenceQueue; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.BooleanSupplier; +import java.util.function.Supplier; + +public class ReferencedKeyTest { + static long BASE_KEY = 10_000_000L; + + public static void main(String[] args) { + mapTest(false, HashMap::new); + mapTest(true, HashMap::new); + mapTest(false, ConcurrentHashMap::new); + mapTest(true, ConcurrentHashMap::new); + + setTest(false, HashMap::new); + setTest(true, HashMap::new); + setTest(false, ConcurrentHashMap::new); + setTest(true, ConcurrentHashMap::new); + } + + static void assertTrue(boolean test, String message) { + if (!test) { + throw new RuntimeException(message); + } + } + + static void mapTest(boolean isSoft, Supplier, String>> supplier) { + Map map = ReferencedKeyMap.create(isSoft, supplier); + populate(map); + if (!isSoft) { + if (!collect(() -> map.isEmpty())) { + throw new RuntimeException("WeakReference map not collecting!"); + } + } + populate(map); + methods(map); + } + + static void setTest(boolean isSoft, Supplier, ReferenceKey>> supplier) { + ReferencedKeySet set = ReferencedKeySet.create(isSoft, supplier); + populate(set); + if (!isSoft) { + if (!collect(() -> set.isEmpty())) { + throw new RuntimeException("WeakReference set not collecting!"); + } + } + populate(set); + methods(set); + } + + static void methods(Map map) { + assertTrue(map.size() == 26, "missing key"); + assertTrue(map.containsKey(BASE_KEY + 'a' -'a'), "missing key"); + assertTrue(map.get(BASE_KEY + 'b' -'a').equals("b"), "wrong key"); + assertTrue(map.containsValue("c"), "missing value"); + map.remove(BASE_KEY + 'd' -'a'); + assertTrue(map.get(BASE_KEY + 'd' -'a') == null, "not removed"); + map.putAll(Map.of(1L, "A", 2L, "B")); + assertTrue(map.get(2L).equals("B"), "collection not added"); + assertTrue(map.containsKey(1L), "key missing"); + assertTrue(map.containsValue("A"), "key missing"); + assertTrue(map.entrySet().contains(Map.entry(1L, "A")), "key missing"); + map.putIfAbsent(3L, "C"); + assertTrue(map.get(3L).equals("C"), "key missing"); + map.putIfAbsent(2L, "D"); + assertTrue(map.get(2L).equals("B"), "key replaced"); + map.remove(3L); + assertTrue(map.get(3L) == null, "key not removed"); + map.replace(2L, "D"); + assertTrue(map.get(2L).equals("D"), "key not replaced"); + map.replace(2L, "B", "E"); + assertTrue(map.get(2L).equals("D"), "key replaced"); + } + + static void methods(ReferencedKeySet set) { + assertTrue(set.size() == 26, "missing key"); + assertTrue(set.contains(BASE_KEY + 3), "missing key"); + set.remove(BASE_KEY + 3); + assertTrue(!set.contains(BASE_KEY + 3), "not removed"); + Long element1 = set.get(BASE_KEY + 2); + Long element2 = set.get(BASE_KEY + 3); + Long element3 = set.get(BASE_KEY + 4); + Long intern1 = set.intern(BASE_KEY + 2); + Long intern2 = set.intern(BASE_KEY + 3); + Long intern3 = set.intern(BASE_KEY + 4, e -> e); + assertTrue(element1 != null, "missing key"); + assertTrue(element2 == null, "not removed"); + assertTrue(element1 == intern1, "intern failed"); // must be same object + assertTrue(intern2 != null, "intern failed"); + assertTrue(element3 == intern3, "intern failed"); + } + + // Borrowed from jdk.test.lib.util.ForceGC but couldn't use from java.base/jdk.internal.util + static boolean collect(BooleanSupplier booleanSupplier) { + ReferenceQueue queue = new ReferenceQueue<>(); + Object obj = new Object(); + PhantomReference ref = new PhantomReference<>(obj, queue); + obj = null; + Reference.reachabilityFence(obj); + Reference.reachabilityFence(ref); + long timeout = 1000L; + long quanta = 200L; + long retries = timeout / quanta; + + for (; retries >= 0; retries--) { + if (booleanSupplier.getAsBoolean()) { + return true; + } + + System.gc(); + + try { + queue.remove(quanta); + } catch (InterruptedException ie) { + // ignore, the loop will try again + } + } + + return booleanSupplier.getAsBoolean(); + } + + static void populate(Map map) { + for (int i = 0; i < 26; i++) { + Long key = BASE_KEY + i; + String value = String.valueOf((char) ('a' + i)); + map.put(key, value); + } + } + + static void populate(Set set) { + for (int i = 0; i < 26; i++) { + Long value = BASE_KEY + i; + set.add(value); + } + } +} From c91a3002fb4304b6184d1d8d5611873c4e028af2 Mon Sep 17 00:00:00 2001 From: Matias Saavedra Silva Date: Mon, 31 Jul 2023 20:23:59 +0000 Subject: [PATCH 10/11] 8307312: Replace "int which" with "int cp_index" in constantPool Reviewed-by: coleenp, dholmes, iklam --- src/hotspot/share/c1/c1_GraphBuilder.cpp | 4 +- src/hotspot/share/ci/ciStreams.cpp | 8 +- src/hotspot/share/ci/ciStreams.hpp | 2 +- src/hotspot/share/ci/ciTypeFlow.cpp | 4 +- src/hotspot/share/interpreter/bytecode.cpp | 4 +- .../share/interpreter/interpreterRuntime.cpp | 6 +- src/hotspot/share/oops/constantPool.cpp | 254 ++++++------ src/hotspot/share/oops/constantPool.hpp | 376 +++++++++--------- 8 files changed, 329 insertions(+), 329 deletions(-) diff --git a/src/hotspot/share/c1/c1_GraphBuilder.cpp b/src/hotspot/share/c1/c1_GraphBuilder.cpp index a51d5e3608a..f62b989e48a 100644 --- a/src/hotspot/share/c1/c1_GraphBuilder.cpp +++ b/src/hotspot/share/c1/c1_GraphBuilder.cpp @@ -998,8 +998,8 @@ void GraphBuilder::load_constant() { // Unbox the value at runtime, if needed. // ConstantDynamic entry can be of a primitive type, but it is cached in boxed form. if (patch_state != nullptr) { - int index = stream()->get_constant_pool_index(); - BasicType type = stream()->get_basic_type_for_constant_at(index); + int cp_index = stream()->get_constant_pool_index(); + BasicType type = stream()->get_basic_type_for_constant_at(cp_index); if (is_java_primitive(type)) { ciInstanceKlass* box_klass = ciEnv::current()->get_box_klass_for_primitive_type(type); assert(box_klass->is_loaded(), "sanity"); diff --git a/src/hotspot/share/ci/ciStreams.cpp b/src/hotspot/share/ci/ciStreams.cpp index 0348eb033ad..95180454c08 100644 --- a/src/hotspot/share/ci/ciStreams.cpp +++ b/src/hotspot/share/ci/ciStreams.cpp @@ -267,9 +267,9 @@ ciConstant ciBytecodeStream::get_constant() { // // If this bytecode is one of the ldc variants, get the referenced // constant. -constantTag ciBytecodeStream::get_constant_pool_tag(int index) const { +constantTag ciBytecodeStream::get_constant_pool_tag(int cp_index) const { VM_ENTRY_MARK; - return _method->get_Method()->constants()->constant_tag_at(index); + return _method->get_Method()->constants()->constant_tag_at(cp_index); } // ------------------------------------------------------------------ @@ -283,9 +283,9 @@ constantTag ciBytecodeStream::get_raw_pool_tag_at(int index) const { // ------------------------------------------------------------------ // ciBytecodeStream::get_basic_type_for_constant_at // -BasicType ciBytecodeStream::get_basic_type_for_constant_at(int index) const { +BasicType ciBytecodeStream::get_basic_type_for_constant_at(int cp_index) const { VM_ENTRY_MARK; - return _method->get_Method()->constants()->basic_type_for_constant_at(index); + return _method->get_Method()->constants()->basic_type_for_constant_at(cp_index); } // ------------------------------------------------------------------ diff --git a/src/hotspot/share/ci/ciStreams.hpp b/src/hotspot/share/ci/ciStreams.hpp index 110002b3b43..e2488e15448 100644 --- a/src/hotspot/share/ci/ciStreams.hpp +++ b/src/hotspot/share/ci/ciStreams.hpp @@ -229,7 +229,7 @@ class ciBytecodeStream : StackObj { // object (ciConstant.as_object()->is_loaded() == false). ciConstant get_constant(); constantTag get_constant_pool_tag(int index) const; - BasicType get_basic_type_for_constant_at(int index) const; + BasicType get_basic_type_for_constant_at(int cp_index) const; constantTag get_raw_pool_tag_at(int index) const; diff --git a/src/hotspot/share/ci/ciTypeFlow.cpp b/src/hotspot/share/ci/ciTypeFlow.cpp index 53c565b47e5..7fec80cff40 100644 --- a/src/hotspot/share/ci/ciTypeFlow.cpp +++ b/src/hotspot/share/ci/ciTypeFlow.cpp @@ -727,8 +727,8 @@ void ciTypeFlow::StateVector::do_ldc(ciBytecodeStream* str) { } ciConstant con = str->get_constant(); if (con.is_valid()) { - int index = str->get_constant_pool_index(); - BasicType basic_type = str->get_basic_type_for_constant_at(index); + int cp_index = str->get_constant_pool_index(); + BasicType basic_type = str->get_basic_type_for_constant_at(cp_index); if (is_reference_type(basic_type)) { ciObject* obj = con.as_object(); if (obj->is_null_object()) { diff --git a/src/hotspot/share/interpreter/bytecode.cpp b/src/hotspot/share/interpreter/bytecode.cpp index cbdf8987cb0..2b23aedef68 100644 --- a/src/hotspot/share/interpreter/bytecode.cpp +++ b/src/hotspot/share/interpreter/bytecode.cpp @@ -217,8 +217,8 @@ int Bytecode_loadconstant::pool_index() const { } BasicType Bytecode_loadconstant::result_type() const { - int index = pool_index(); - return _method->constants()->basic_type_for_constant_at(index); + int cp_index = pool_index(); + return _method->constants()->basic_type_for_constant_at(cp_index); } oop Bytecode_loadconstant::resolve_constant(TRAPS) const { diff --git a/src/hotspot/share/interpreter/interpreterRuntime.cpp b/src/hotspot/share/interpreter/interpreterRuntime.cpp index 33590308976..8306dcd7f23 100644 --- a/src/hotspot/share/interpreter/interpreterRuntime.cpp +++ b/src/hotspot/share/interpreter/interpreterRuntime.cpp @@ -151,11 +151,11 @@ JRT_ENTRY(void, InterpreterRuntime::ldc(JavaThread* current, bool wide)) // access constant pool LastFrameAccessor last_frame(current); ConstantPool* pool = last_frame.method()->constants(); - int index = wide ? last_frame.get_index_u2(Bytecodes::_ldc_w) : last_frame.get_index_u1(Bytecodes::_ldc); - constantTag tag = pool->tag_at(index); + int cp_index = wide ? last_frame.get_index_u2(Bytecodes::_ldc_w) : last_frame.get_index_u1(Bytecodes::_ldc); + constantTag tag = pool->tag_at(cp_index); assert (tag.is_unresolved_klass() || tag.is_klass(), "wrong ldc call"); - Klass* klass = pool->klass_at(index, CHECK); + Klass* klass = pool->klass_at(cp_index, CHECK); oop java_class = klass->java_mirror(); current->set_vm_result(java_class); JRT_END diff --git a/src/hotspot/share/oops/constantPool.cpp b/src/hotspot/share/oops/constantPool.cpp index 9840ba5cf66..ade9f2e027b 100644 --- a/src/hotspot/share/oops/constantPool.cpp +++ b/src/hotspot/share/oops/constantPool.cpp @@ -382,22 +382,22 @@ void ConstantPool::remove_unshareable_info() { set_resolved_references(OopHandle()); bool archived = false; - for (int index = 1; index < length(); index++) { // Index 0 is unused - switch (tag_at(index).value()) { + for (int cp_index = 1; cp_index < length(); cp_index++) { // cp_index 0 is unused + switch (tag_at(cp_index).value()) { case JVM_CONSTANT_UnresolvedClassInError: - tag_at_put(index, JVM_CONSTANT_UnresolvedClass); + tag_at_put(cp_index, JVM_CONSTANT_UnresolvedClass); break; case JVM_CONSTANT_MethodHandleInError: - tag_at_put(index, JVM_CONSTANT_MethodHandle); + tag_at_put(cp_index, JVM_CONSTANT_MethodHandle); break; case JVM_CONSTANT_MethodTypeInError: - tag_at_put(index, JVM_CONSTANT_MethodType); + tag_at_put(cp_index, JVM_CONSTANT_MethodType); break; case JVM_CONSTANT_DynamicInError: - tag_at_put(index, JVM_CONSTANT_Dynamic); + tag_at_put(cp_index, JVM_CONSTANT_Dynamic); break; case JVM_CONSTANT_Class: - archived = maybe_archive_resolved_klass_at(index); + archived = maybe_archive_resolved_klass_at(cp_index); ArchiveBuilder::alloc_stats()->record_klass_cp_entry(archived); break; } @@ -453,7 +453,7 @@ int ConstantPool::cp_to_object_index(int cp_index) { return (i < 0) ? _no_index_sentinel : i; } -void ConstantPool::string_at_put(int which, int obj_index, oop str) { +void ConstantPool::string_at_put(int obj_index, oop str) { oop result = set_resolved_reference_at(obj_index, str); assert(result == nullptr || result == str, "Only set once or to the same string."); } @@ -487,21 +487,21 @@ void ConstantPool::trace_class_resolution(const constantPoolHandle& this_cp, Kla } } -Klass* ConstantPool::klass_at_impl(const constantPoolHandle& this_cp, int which, +Klass* ConstantPool::klass_at_impl(const constantPoolHandle& this_cp, int cp_index, TRAPS) { JavaThread* javaThread = THREAD; // A resolved constantPool entry will contain a Klass*, otherwise a Symbol*. // It is not safe to rely on the tag bit's here, since we don't have a lock, and // the entry and tag is not updated atomically. - CPKlassSlot kslot = this_cp->klass_slot_at(which); + CPKlassSlot kslot = this_cp->klass_slot_at(cp_index); int resolved_klass_index = kslot.resolved_klass_index(); int name_index = kslot.name_index(); assert(this_cp->tag_at(name_index).is_symbol(), "sanity"); // The tag must be JVM_CONSTANT_Class in order to read the correct value from // the unresolved_klasses() array. - if (this_cp->tag_at(which).is_klass()) { + if (this_cp->tag_at(cp_index).is_klass()) { Klass* klass = this_cp->resolved_klasses()->at(resolved_klass_index); if (klass != nullptr) { return klass; @@ -509,7 +509,7 @@ Klass* ConstantPool::klass_at_impl(const constantPoolHandle& this_cp, int which, } // This tag doesn't change back to unresolved class unless at a safepoint. - if (this_cp->tag_at(which).is_unresolved_klass_in_error()) { + if (this_cp->tag_at(cp_index).is_unresolved_klass_in_error()) { // The original attempt to resolve this constant pool entry failed so find the // class of the original error and throw another error of the same class // (JVMS 5.4.3). @@ -518,7 +518,7 @@ Klass* ConstantPool::klass_at_impl(const constantPoolHandle& this_cp, int which, // or any internal exception fields such as cause or stacktrace. But since the // detail message is often a class name or other literal string, we will repeat it // if we can find it in the symbol table. - throw_resolution_error(this_cp, which, CHECK_NULL); + throw_resolution_error(this_cp, cp_index, CHECK_NULL); ShouldNotReachHere(); } @@ -545,7 +545,7 @@ Klass* ConstantPool::klass_at_impl(const constantPoolHandle& this_cp, int which, // Failed to resolve class. We must record the errors so that subsequent attempts // to resolve this constant pool entry fail with the same error (JVMS 5.4.3). if (HAS_PENDING_EXCEPTION) { - save_and_throw_exception(this_cp, which, constantTag(JVM_CONSTANT_UnresolvedClass), CHECK_NULL); + save_and_throw_exception(this_cp, cp_index, constantTag(JVM_CONSTANT_UnresolvedClass), CHECK_NULL); // If CHECK_NULL above doesn't return the exception, that means that // some other thread has beaten us and has resolved the class. // To preserve old behavior, we return the resolved class. @@ -566,7 +566,7 @@ Klass* ConstantPool::klass_at_impl(const constantPoolHandle& this_cp, int which, // hardware store ordering here. // We also need to CAS to not overwrite an error from a racing thread. - jbyte old_tag = Atomic::cmpxchg((jbyte*)this_cp->tag_addr_at(which), + jbyte old_tag = Atomic::cmpxchg((jbyte*)this_cp->tag_addr_at(cp_index), (jbyte)JVM_CONSTANT_UnresolvedClass, (jbyte)JVM_CONSTANT_Class); @@ -574,7 +574,7 @@ Klass* ConstantPool::klass_at_impl(const constantPoolHandle& this_cp, int which, if (old_tag == JVM_CONSTANT_UnresolvedClassInError) { // Remove klass. this_cp->resolved_klasses()->at_put(resolved_klass_index, nullptr); - throw_resolution_error(this_cp, which, CHECK_NULL); + throw_resolution_error(this_cp, cp_index, CHECK_NULL); } return k; @@ -754,14 +754,14 @@ void ConstantPool::verify_constant_pool_resolve(const constantPoolHandle& this_c } -u2 ConstantPool::name_ref_index_at(int which_nt) { - jint ref_index = name_and_type_at(which_nt); +u2 ConstantPool::name_ref_index_at(int cp_index) { + jint ref_index = name_and_type_at(cp_index); return extract_low_short_from_int(ref_index); } -u2 ConstantPool::signature_ref_index_at(int which_nt) { - jint ref_index = name_and_type_at(which_nt); +u2 ConstantPool::signature_ref_index_at(int cp_index) { + jint ref_index = name_and_type_at(cp_index); return extract_high_short_from_int(ref_index); } @@ -770,8 +770,8 @@ Klass* ConstantPool::klass_ref_at(int which, Bytecodes::Code code, TRAPS) { return klass_at(klass_ref_index_at(which, code), THREAD); } -Symbol* ConstantPool::klass_name_at(int which) const { - return symbol_at(klass_slot_at(which).name_index()); +Symbol* ConstantPool::klass_name_at(int cp_index) const { + return symbol_at(klass_slot_at(cp_index).name_index()); } Symbol* ConstantPool::klass_ref_at_noresolve(int which, Bytecodes::Code code) { @@ -779,17 +779,17 @@ Symbol* ConstantPool::klass_ref_at_noresolve(int which, Bytecodes::Code code) { return klass_at_noresolve(ref_index); } -Symbol* ConstantPool::uncached_klass_ref_at_noresolve(int which) { - jint ref_index = uncached_klass_ref_index_at(which); +Symbol* ConstantPool::uncached_klass_ref_at_noresolve(int cp_index) { + jint ref_index = uncached_klass_ref_index_at(cp_index); return klass_at_noresolve(ref_index); } -char* ConstantPool::string_at_noresolve(int which) { - return unresolved_string_at(which)->as_C_string(); +char* ConstantPool::string_at_noresolve(int cp_index) { + return unresolved_string_at(cp_index)->as_C_string(); } -BasicType ConstantPool::basic_type_for_signature_at(int which) const { - return Signature::basic_type(symbol_at(which)); +BasicType ConstantPool::basic_type_for_signature_at(int cp_index) const { + return Signature::basic_type(symbol_at(cp_index)); } @@ -882,7 +882,7 @@ void ConstantPool::throw_resolution_error(const constantPoolHandle& this_cp, int // If resolution for Class, Dynamic constant, MethodHandle or MethodType fails, save the // exception in the resolution error table, so that the same exception is thrown again. -void ConstantPool::save_and_throw_exception(const constantPoolHandle& this_cp, int which, +void ConstantPool::save_and_throw_exception(const constantPoolHandle& this_cp, int cp_index, constantTag tag, TRAPS) { int error_tag = tag.error_value(); @@ -893,44 +893,44 @@ void ConstantPool::save_and_throw_exception(const constantPoolHandle& this_cp, i // being loaded due to virtual machine errors like StackOverflow // and OutOfMemoryError, etc, or if the thread was hit by stop() // Needs clarification to section 5.4.3 of the VM spec (see 6308271) - } else if (this_cp->tag_at(which).value() != error_tag) { - add_resolution_error(this_cp, which, tag, PENDING_EXCEPTION); + } else if (this_cp->tag_at(cp_index).value() != error_tag) { + add_resolution_error(this_cp, cp_index, tag, PENDING_EXCEPTION); // CAS in the tag. If a thread beat us to registering this error that's fine. // If another thread resolved the reference, this is a race condition. This // thread may have had a security manager or something temporary. // This doesn't deterministically get an error. So why do we save this? // We save this because jvmti can add classes to the bootclass path after // this error, so it needs to get the same error if the error is first. - jbyte old_tag = Atomic::cmpxchg((jbyte*)this_cp->tag_addr_at(which), + jbyte old_tag = Atomic::cmpxchg((jbyte*)this_cp->tag_addr_at(cp_index), (jbyte)tag.value(), (jbyte)error_tag); if (old_tag != error_tag && old_tag != tag.value()) { // MethodHandles and MethodType doesn't change to resolved version. - assert(this_cp->tag_at(which).is_klass(), "Wrong tag value"); + assert(this_cp->tag_at(cp_index).is_klass(), "Wrong tag value"); // Forget the exception and use the resolved class. CLEAR_PENDING_EXCEPTION; } } else { // some other thread put this in error state - throw_resolution_error(this_cp, which, CHECK); + throw_resolution_error(this_cp, cp_index, CHECK); } } -constantTag ConstantPool::constant_tag_at(int which) { - constantTag tag = tag_at(which); +constantTag ConstantPool::constant_tag_at(int cp_index) { + constantTag tag = tag_at(cp_index); if (tag.is_dynamic_constant()) { - BasicType bt = basic_type_for_constant_at(which); + BasicType bt = basic_type_for_constant_at(cp_index); return constantTag(constantTag::type2tag(bt)); } return tag; } -BasicType ConstantPool::basic_type_for_constant_at(int which) { - constantTag tag = tag_at(which); +BasicType ConstantPool::basic_type_for_constant_at(int cp_index) { + constantTag tag = tag_at(cp_index); if (tag.is_dynamic_constant() || tag.is_dynamic_constant_in_error()) { // have to look at the signature for this one - Symbol* constant_type = uncached_signature_ref_at(which); + Symbol* constant_type = uncached_signature_ref_at(cp_index); return Signature::basic_type(constant_type); } return tag.basic_type(); @@ -940,7 +940,7 @@ BasicType ConstantPool::basic_type_for_constant_at(int which) { // Some constant pool entries cache their resolved oop. This is also // called to create oops from constants to use in arguments for invokedynamic oop ConstantPool::resolve_constant_at_impl(const constantPoolHandle& this_cp, - int index, int cache_index, + int cp_index, int cache_index, bool* status_return, TRAPS) { oop result_oop = nullptr; @@ -949,17 +949,17 @@ oop ConstantPool::resolve_constant_at_impl(const constantPoolHandle& this_cp, // We'll do a linear search. This should be OK because this usage is rare. // FIXME: If bootstrap specifiers stress this code, consider putting in // a reverse index. Binary search over a short array should do it. - assert(index > 0, "valid index"); - cache_index = this_cp->cp_to_object_index(index); + assert(cp_index > 0, "valid constant pool index"); + cache_index = this_cp->cp_to_object_index(cp_index); } assert(cache_index == _no_index_sentinel || cache_index >= 0, ""); - assert(index == _no_index_sentinel || index >= 0, ""); + assert(cp_index == _no_index_sentinel || cp_index >= 0, ""); if (cache_index >= 0) { result_oop = this_cp->resolved_reference_at(cache_index); if (result_oop != nullptr) { if (result_oop == Universe::the_null_sentinel()) { - DEBUG_ONLY(int temp_index = (index >= 0 ? index : this_cp->object_to_cp_index(cache_index))); + DEBUG_ONLY(int temp_index = (cp_index >= 0 ? cp_index : this_cp->object_to_cp_index(cache_index))); assert(this_cp->tag_at(temp_index).is_dynamic_constant(), "only condy uses the null sentinel"); result_oop = nullptr; } @@ -967,19 +967,19 @@ oop ConstantPool::resolve_constant_at_impl(const constantPoolHandle& this_cp, return result_oop; // That was easy... } - index = this_cp->object_to_cp_index(cache_index); + cp_index = this_cp->object_to_cp_index(cache_index); } jvalue prim_value; // temp used only in a few cases below - constantTag tag = this_cp->tag_at(index); + constantTag tag = this_cp->tag_at(cp_index); if (status_return != nullptr) { // don't trigger resolution if the constant might need it switch (tag.value()) { case JVM_CONSTANT_Class: { - CPKlassSlot kslot = this_cp->klass_slot_at(index); + CPKlassSlot kslot = this_cp->klass_slot_at(cp_index); int resolved_klass_index = kslot.resolved_klass_index(); if (this_cp->resolved_klasses()->at(resolved_klass_index) == nullptr) { (*status_return) = false; @@ -1009,7 +1009,7 @@ oop ConstantPool::resolve_constant_at_impl(const constantPoolHandle& this_cp, case JVM_CONSTANT_Class: { assert(cache_index == _no_index_sentinel, "should not have been set"); - Klass* resolved = klass_at_impl(this_cp, index, CHECK_NULL); + Klass* resolved = klass_at_impl(this_cp, cp_index, CHECK_NULL); // ldc wants the java mirror. result_oop = resolved->java_mirror(); break; @@ -1018,7 +1018,7 @@ oop ConstantPool::resolve_constant_at_impl(const constantPoolHandle& this_cp, case JVM_CONSTANT_Dynamic: { // Resolve the Dynamically-Computed constant to invoke the BSM in order to obtain the resulting oop. - BootstrapInfo bootstrap_specifier(this_cp, index); + BootstrapInfo bootstrap_specifier(this_cp, cp_index); // The initial step in resolving an unresolved symbolic reference to a // dynamically-computed constant is to resolve the symbolic reference to a @@ -1036,7 +1036,7 @@ oop ConstantPool::resolve_constant_at_impl(const constantPoolHandle& this_cp, if (HAS_PENDING_EXCEPTION) { // Resolution failure of the dynamically-computed constant, save_and_throw_exception // will check for a LinkageError and store a DynamicConstantInError. - save_and_throw_exception(this_cp, index, tag, CHECK_NULL); + save_and_throw_exception(this_cp, cp_index, tag, CHECK_NULL); } result_oop = bootstrap_specifier.resolved_value()(); BasicType type = Signature::basic_type(bootstrap_specifier.signature()); @@ -1070,25 +1070,25 @@ oop ConstantPool::resolve_constant_at_impl(const constantPoolHandle& this_cp, case JVM_CONSTANT_String: assert(cache_index != _no_index_sentinel, "should have been set"); - result_oop = string_at_impl(this_cp, index, cache_index, CHECK_NULL); + result_oop = string_at_impl(this_cp, cp_index, cache_index, CHECK_NULL); break; case JVM_CONSTANT_MethodHandle: { - int ref_kind = this_cp->method_handle_ref_kind_at(index); - int callee_index = this_cp->method_handle_klass_index_at(index); - Symbol* name = this_cp->method_handle_name_ref_at(index); - Symbol* signature = this_cp->method_handle_signature_ref_at(index); - constantTag m_tag = this_cp->tag_at(this_cp->method_handle_index_at(index)); + int ref_kind = this_cp->method_handle_ref_kind_at(cp_index); + int callee_index = this_cp->method_handle_klass_index_at(cp_index); + Symbol* name = this_cp->method_handle_name_ref_at(cp_index); + Symbol* signature = this_cp->method_handle_signature_ref_at(cp_index); + constantTag m_tag = this_cp->tag_at(this_cp->method_handle_index_at(cp_index)); { ResourceMark rm(THREAD); log_debug(class, resolve)("resolve JVM_CONSTANT_MethodHandle:%d [%d/%d/%d] %s.%s", - ref_kind, index, this_cp->method_handle_index_at(index), + ref_kind, cp_index, this_cp->method_handle_index_at(cp_index), callee_index, name->as_C_string(), signature->as_C_string()); } Klass* callee = klass_at_impl(this_cp, callee_index, THREAD); if (HAS_PENDING_EXCEPTION) { - save_and_throw_exception(this_cp, index, tag, CHECK_NULL); + save_and_throw_exception(this_cp, cp_index, tag, CHECK_NULL); } // Check constant pool method consistency @@ -1102,11 +1102,11 @@ oop ConstantPool::resolve_constant_at_impl(const constantPoolHandle& this_cp, ss.print(" %s(", name->as_C_string()); signature->print_as_signature_external_parameters(&ss); ss.print(")' at index %d is %s and should be %s", - index, + cp_index, callee->is_interface() ? "CONSTANT_MethodRef" : "CONSTANT_InterfaceMethodRef", callee->is_interface() ? "CONSTANT_InterfaceMethodRef" : "CONSTANT_MethodRef"); Exceptions::fthrow(THREAD_AND_LOCATION, vmSymbols::java_lang_IncompatibleClassChangeError(), "%s", ss.as_string()); - save_and_throw_exception(this_cp, index, tag, CHECK_NULL); + save_and_throw_exception(this_cp, cp_index, tag, CHECK_NULL); } Klass* klass = this_cp->pool_holder(); @@ -1115,7 +1115,7 @@ oop ConstantPool::resolve_constant_at_impl(const constantPoolHandle& this_cp, callee, name, signature, THREAD); if (HAS_PENDING_EXCEPTION) { - save_and_throw_exception(this_cp, index, tag, CHECK_NULL); + save_and_throw_exception(this_cp, cp_index, tag, CHECK_NULL); } result_oop = value(); break; @@ -1123,10 +1123,10 @@ oop ConstantPool::resolve_constant_at_impl(const constantPoolHandle& this_cp, case JVM_CONSTANT_MethodType: { - Symbol* signature = this_cp->method_type_signature_at(index); + Symbol* signature = this_cp->method_type_signature_at(cp_index); { ResourceMark rm(THREAD); log_debug(class, resolve)("resolve JVM_CONSTANT_MethodType [%d/%d] %s", - index, this_cp->method_type_index_at(index), + cp_index, this_cp->method_type_index_at(cp_index), signature->as_C_string()); } Klass* klass = this_cp->pool_holder(); @@ -1134,32 +1134,32 @@ oop ConstantPool::resolve_constant_at_impl(const constantPoolHandle& this_cp, Handle value = SystemDictionary::find_method_handle_type(signature, klass, THREAD); result_oop = value(); if (HAS_PENDING_EXCEPTION) { - save_and_throw_exception(this_cp, index, tag, CHECK_NULL); + save_and_throw_exception(this_cp, cp_index, tag, CHECK_NULL); } break; } case JVM_CONSTANT_Integer: assert(cache_index == _no_index_sentinel, "should not have been set"); - prim_value.i = this_cp->int_at(index); + prim_value.i = this_cp->int_at(cp_index); result_oop = java_lang_boxing_object::create(T_INT, &prim_value, CHECK_NULL); break; case JVM_CONSTANT_Float: assert(cache_index == _no_index_sentinel, "should not have been set"); - prim_value.f = this_cp->float_at(index); + prim_value.f = this_cp->float_at(cp_index); result_oop = java_lang_boxing_object::create(T_FLOAT, &prim_value, CHECK_NULL); break; case JVM_CONSTANT_Long: assert(cache_index == _no_index_sentinel, "should not have been set"); - prim_value.j = this_cp->long_at(index); + prim_value.j = this_cp->long_at(cp_index); result_oop = java_lang_boxing_object::create(T_LONG, &prim_value, CHECK_NULL); break; case JVM_CONSTANT_Double: assert(cache_index == _no_index_sentinel, "should not have been set"); - prim_value.d = this_cp->double_at(index); + prim_value.d = this_cp->double_at(cp_index); result_oop = java_lang_boxing_object::create(T_DOUBLE, &prim_value, CHECK_NULL); break; @@ -1167,11 +1167,11 @@ oop ConstantPool::resolve_constant_at_impl(const constantPoolHandle& this_cp, case JVM_CONSTANT_DynamicInError: case JVM_CONSTANT_MethodHandleInError: case JVM_CONSTANT_MethodTypeInError: - throw_resolution_error(this_cp, index, CHECK_NULL); + throw_resolution_error(this_cp, cp_index, CHECK_NULL); break; default: - fatal("unexpected constant tag at CP %p[%d/%d] = %d", this_cp(), index, cache_index, tag.value()); + fatal("unexpected constant tag at CP %p[%d/%d] = %d", this_cp(), cp_index, cache_index, tag.value()); break; } @@ -1197,27 +1197,27 @@ oop ConstantPool::resolve_constant_at_impl(const constantPoolHandle& this_cp, } } -oop ConstantPool::uncached_string_at(int which, TRAPS) { - Symbol* sym = unresolved_string_at(which); +oop ConstantPool::uncached_string_at(int cp_index, TRAPS) { + Symbol* sym = unresolved_string_at(cp_index); oop str = StringTable::intern(sym, CHECK_(nullptr)); assert(java_lang_String::is_instance(str), "must be string"); return str; } -void ConstantPool::copy_bootstrap_arguments_at_impl(const constantPoolHandle& this_cp, int index, +void ConstantPool::copy_bootstrap_arguments_at_impl(const constantPoolHandle& this_cp, int cp_index, int start_arg, int end_arg, objArrayHandle info, int pos, bool must_resolve, Handle if_not_available, TRAPS) { int limit = pos + end_arg - start_arg; - // checks: index in range [0..this_cp->length), - // tag at index, start..end in range [0..this_cp->bootstrap_argument_count], + // checks: cp_index in range [0..this_cp->length), + // tag at cp_index, start..end in range [0..this_cp->bootstrap_argument_count], // info array non-null, pos..limit in [0..info.length] - if ((0 >= index || index >= this_cp->length()) || - !(this_cp->tag_at(index).is_invoke_dynamic() || - this_cp->tag_at(index).is_dynamic_constant()) || + if ((0 >= cp_index || cp_index >= this_cp->length()) || + !(this_cp->tag_at(cp_index).is_invoke_dynamic() || + this_cp->tag_at(cp_index).is_dynamic_constant()) || (0 > start_arg || start_arg > end_arg) || - (end_arg > this_cp->bootstrap_argument_count_at(index)) || + (end_arg > this_cp->bootstrap_argument_count_at(cp_index)) || (0 > pos || pos > limit) || (info.is_null() || limit > info->length())) { // An index or something else went wrong; throw an error. @@ -1228,7 +1228,7 @@ void ConstantPool::copy_bootstrap_arguments_at_impl(const constantPoolHandle& th // now we can loop safely int info_i = pos; for (int i = start_arg; i < end_arg; i++) { - int arg_index = this_cp->bootstrap_argument_index_at(index, i); + int arg_index = this_cp->bootstrap_argument_index_at(cp_index, i); oop arg_oop; if (must_resolve) { arg_oop = this_cp->resolve_possibly_cached_constant_at(arg_index, CHECK); @@ -1241,22 +1241,22 @@ void ConstantPool::copy_bootstrap_arguments_at_impl(const constantPoolHandle& th } } -oop ConstantPool::string_at_impl(const constantPoolHandle& this_cp, int which, int obj_index, TRAPS) { +oop ConstantPool::string_at_impl(const constantPoolHandle& this_cp, int cp_index, int obj_index, TRAPS) { // If the string has already been interned, this entry will be non-null oop str = this_cp->resolved_reference_at(obj_index); assert(str != Universe::the_null_sentinel(), ""); if (str != nullptr) return str; - Symbol* sym = this_cp->unresolved_string_at(which); + Symbol* sym = this_cp->unresolved_string_at(cp_index); str = StringTable::intern(sym, CHECK_(nullptr)); - this_cp->string_at_put(which, obj_index, str); + this_cp->string_at_put(obj_index, str); assert(java_lang_String::is_instance(str), "must be string"); return str; } -bool ConstantPool::klass_name_at_matches(const InstanceKlass* k, int which) { +bool ConstantPool::klass_name_at_matches(const InstanceKlass* k, int cp_index) { // Names are interned, so we can compare Symbol*s directly - Symbol* cp_name = klass_name_at(which); + Symbol* cp_name = klass_name_at(cp_index); return (cp_name == k->name()); } @@ -1614,23 +1614,23 @@ void ConstantPool::copy_cp_to_impl(const constantPoolHandle& from_cp, int start_ const constantPoolHandle& to_cp, int to_i, TRAPS) { - int dest_i = to_i; // leave original alone for debug purposes + int dest_cpi = to_i; // leave original alone for debug purposes - for (int src_i = start_i; src_i <= end_i; /* see loop bottom */ ) { - copy_entry_to(from_cp, src_i, to_cp, dest_i); + for (int src_cpi = start_i; src_cpi <= end_i; /* see loop bottom */ ) { + copy_entry_to(from_cp, src_cpi, to_cp, dest_cpi); - switch (from_cp->tag_at(src_i).value()) { + switch (from_cp->tag_at(src_cpi).value()) { case JVM_CONSTANT_Double: case JVM_CONSTANT_Long: // double and long take two constant pool entries - src_i += 2; - dest_i += 2; + src_cpi += 2; + dest_cpi += 2; break; default: // all others take one constant pool entry - src_i++; - dest_i++; + src_cpi++; + dest_cpi++; break; } } @@ -1842,16 +1842,16 @@ int ConstantPool::find_matching_operand(int pattern_i, #ifndef PRODUCT -const char* ConstantPool::printable_name_at(int which) { +const char* ConstantPool::printable_name_at(int cp_index) { - constantTag tag = tag_at(which); + constantTag tag = tag_at(cp_index); if (tag.is_string()) { - return string_at_noresolve(which); + return string_at_noresolve(cp_index); } else if (tag.is_klass() || tag.is_unresolved_klass()) { - return klass_name_at(which)->as_C_string(); + return klass_name_at(cp_index)->as_C_string(); } else if (tag.is_symbol()) { - return symbol_at(which)->as_C_string(); + return symbol_at(cp_index)->as_C_string(); } return ""; } @@ -2320,14 +2320,14 @@ void ConstantPool::print_on(outputStream* st) const { } // Print one constant pool entry -void ConstantPool::print_entry_on(const int index, outputStream* st) { +void ConstantPool::print_entry_on(const int cp_index, outputStream* st) { EXCEPTION_MARK; - st->print(" - %3d : ", index); - tag_at(index).print_on(st); + st->print(" - %3d : ", cp_index); + tag_at(cp_index).print_on(st); st->print(" : "); - switch (tag_at(index).value()) { + switch (tag_at(cp_index).value()) { case JVM_CONSTANT_Class : - { Klass* k = klass_at(index, CATCH); + { Klass* k = klass_at(cp_index, CATCH); guarantee(k != nullptr, "need klass"); k->print_value_on(st); st->print(" {" PTR_FORMAT "}", p2i(k)); @@ -2336,40 +2336,40 @@ void ConstantPool::print_entry_on(const int index, outputStream* st) { case JVM_CONSTANT_Fieldref : case JVM_CONSTANT_Methodref : case JVM_CONSTANT_InterfaceMethodref : - st->print("klass_index=%d", uncached_klass_ref_index_at(index)); - st->print(" name_and_type_index=%d", uncached_name_and_type_ref_index_at(index)); + st->print("klass_index=%d", uncached_klass_ref_index_at(cp_index)); + st->print(" name_and_type_index=%d", uncached_name_and_type_ref_index_at(cp_index)); break; case JVM_CONSTANT_String : - unresolved_string_at(index)->print_value_on(st); + unresolved_string_at(cp_index)->print_value_on(st); break; case JVM_CONSTANT_Integer : - st->print("%d", int_at(index)); + st->print("%d", int_at(cp_index)); break; case JVM_CONSTANT_Float : - st->print("%f", float_at(index)); + st->print("%f", float_at(cp_index)); break; case JVM_CONSTANT_Long : - st->print_jlong(long_at(index)); + st->print_jlong(long_at(cp_index)); break; case JVM_CONSTANT_Double : - st->print("%lf", double_at(index)); + st->print("%lf", double_at(cp_index)); break; case JVM_CONSTANT_NameAndType : - st->print("name_index=%d", name_ref_index_at(index)); - st->print(" signature_index=%d", signature_ref_index_at(index)); + st->print("name_index=%d", name_ref_index_at(cp_index)); + st->print(" signature_index=%d", signature_ref_index_at(cp_index)); break; case JVM_CONSTANT_Utf8 : - symbol_at(index)->print_value_on(st); + symbol_at(cp_index)->print_value_on(st); break; case JVM_CONSTANT_ClassIndex: { - int name_index = *int_at_addr(index); + int name_index = *int_at_addr(cp_index); st->print("klass_index=%d ", name_index); symbol_at(name_index)->print_value_on(st); } break; case JVM_CONSTANT_UnresolvedClass : // fall-through case JVM_CONSTANT_UnresolvedClassInError: { - CPKlassSlot kslot = klass_slot_at(index); + CPKlassSlot kslot = klass_slot_at(cp_index); int resolved_klass_index = kslot.resolved_klass_index(); int name_index = kslot.name_index(); assert(tag_at(name_index).is_symbol(), "sanity"); @@ -2378,22 +2378,22 @@ void ConstantPool::print_entry_on(const int index, outputStream* st) { break; case JVM_CONSTANT_MethodHandle : case JVM_CONSTANT_MethodHandleInError : - st->print("ref_kind=%d", method_handle_ref_kind_at(index)); - st->print(" ref_index=%d", method_handle_index_at(index)); + st->print("ref_kind=%d", method_handle_ref_kind_at(cp_index)); + st->print(" ref_index=%d", method_handle_index_at(cp_index)); break; case JVM_CONSTANT_MethodType : case JVM_CONSTANT_MethodTypeInError : - st->print("signature_index=%d", method_type_index_at(index)); + st->print("signature_index=%d", method_type_index_at(cp_index)); break; case JVM_CONSTANT_Dynamic : case JVM_CONSTANT_DynamicInError : { - st->print("bootstrap_method_index=%d", bootstrap_method_ref_index_at(index)); - st->print(" type_index=%d", bootstrap_name_and_type_ref_index_at(index)); - int argc = bootstrap_argument_count_at(index); + st->print("bootstrap_method_index=%d", bootstrap_method_ref_index_at(cp_index)); + st->print(" type_index=%d", bootstrap_name_and_type_ref_index_at(cp_index)); + int argc = bootstrap_argument_count_at(cp_index); if (argc > 0) { for (int arg_i = 0; arg_i < argc; arg_i++) { - int arg = bootstrap_argument_index_at(index, arg_i); + int arg = bootstrap_argument_index_at(cp_index, arg_i); st->print((arg_i == 0 ? " arguments={%d" : ", %d"), arg); } st->print("}"); @@ -2402,12 +2402,12 @@ void ConstantPool::print_entry_on(const int index, outputStream* st) { break; case JVM_CONSTANT_InvokeDynamic : { - st->print("bootstrap_method_index=%d", bootstrap_method_ref_index_at(index)); - st->print(" name_and_type_index=%d", bootstrap_name_and_type_ref_index_at(index)); - int argc = bootstrap_argument_count_at(index); + st->print("bootstrap_method_index=%d", bootstrap_method_ref_index_at(cp_index)); + st->print(" name_and_type_index=%d", bootstrap_name_and_type_ref_index_at(cp_index)); + int argc = bootstrap_argument_count_at(cp_index); if (argc > 0) { for (int arg_i = 0; arg_i < argc; arg_i++) { - int arg = bootstrap_argument_index_at(index, arg_i); + int arg = bootstrap_argument_index_at(cp_index, arg_i); st->print((arg_i == 0 ? " arguments={%d" : ", %d"), arg); } st->print("}"); diff --git a/src/hotspot/share/oops/constantPool.hpp b/src/hotspot/share/oops/constantPool.hpp index 5a92ece4512..3a6dd3cc752 100644 --- a/src/hotspot/share/oops/constantPool.hpp +++ b/src/hotspot/share/oops/constantPool.hpp @@ -122,11 +122,11 @@ class ConstantPool : public Metadata { int _version; } _saved; - void set_tags(Array* tags) { _tags = tags; } - void tag_at_put(int which, jbyte t) { tags()->at_put(which, t); } - void release_tag_at_put(int which, jbyte t) { tags()->release_at_put(which, t); } + void set_tags(Array* tags) { _tags = tags; } + void tag_at_put(int cp_index, jbyte t) { tags()->at_put(cp_index, t); } + void release_tag_at_put(int cp_index, jbyte t) { tags()->release_at_put(cp_index, t); } - u1* tag_addr_at(int which) const { return tags()->adr_at(which); } + u1* tag_addr_at(int cp_index) const { return tags()->adr_at(cp_index); } void set_operands(Array* operands) { _operands = operands; } @@ -136,29 +136,29 @@ class ConstantPool : public Metadata { private: intptr_t* base() const { return (intptr_t*) (((char*) this) + sizeof(ConstantPool)); } - intptr_t* obj_at_addr(int which) const { - assert(is_within_bounds(which), "index out of bounds"); - return (intptr_t*) &base()[which]; + intptr_t* obj_at_addr(int cp_index) const { + assert(is_within_bounds(cp_index), "index out of bounds"); + return (intptr_t*) &base()[cp_index]; } - jint* int_at_addr(int which) const { - assert(is_within_bounds(which), "index out of bounds"); - return (jint*) &base()[which]; + jint* int_at_addr(int cp_index) const { + assert(is_within_bounds(cp_index), "index out of bounds"); + return (jint*) &base()[cp_index]; } - jlong* long_at_addr(int which) const { - assert(is_within_bounds(which), "index out of bounds"); - return (jlong*) &base()[which]; + jlong* long_at_addr(int cp_index) const { + assert(is_within_bounds(cp_index), "index out of bounds"); + return (jlong*) &base()[cp_index]; } - jfloat* float_at_addr(int which) const { - assert(is_within_bounds(which), "index out of bounds"); - return (jfloat*) &base()[which]; + jfloat* float_at_addr(int cp_index) const { + assert(is_within_bounds(cp_index), "index out of bounds"); + return (jfloat*) &base()[cp_index]; } - jdouble* double_at_addr(int which) const { - assert(is_within_bounds(which), "index out of bounds"); - return (jdouble*) &base()[which]; + jdouble* double_at_addr(int cp_index) const { + assert(is_within_bounds(cp_index), "index out of bounds"); + return (jdouble*) &base()[cp_index]; } ConstantPool(Array* tags); @@ -270,260 +270,260 @@ class ConstantPool : public Metadata { // Storing constants // For temporary use while constructing constant pool - void klass_index_at_put(int which, int name_index) { - tag_at_put(which, JVM_CONSTANT_ClassIndex); - *int_at_addr(which) = name_index; + void klass_index_at_put(int cp_index, int name_index) { + tag_at_put(cp_index, JVM_CONSTANT_ClassIndex); + *int_at_addr(cp_index) = name_index; } // Hidden class support: void klass_at_put(int class_index, Klass* k); - void unresolved_klass_at_put(int which, int name_index, int resolved_klass_index) { - release_tag_at_put(which, JVM_CONSTANT_UnresolvedClass); + void unresolved_klass_at_put(int cp_index, int name_index, int resolved_klass_index) { + release_tag_at_put(cp_index, JVM_CONSTANT_UnresolvedClass); assert((name_index & 0xffff0000) == 0, "must be"); assert((resolved_klass_index & 0xffff0000) == 0, "must be"); - *int_at_addr(which) = + *int_at_addr(cp_index) = build_int_from_shorts((jushort)resolved_klass_index, (jushort)name_index); } - void method_handle_index_at_put(int which, int ref_kind, int ref_index) { - tag_at_put(which, JVM_CONSTANT_MethodHandle); - *int_at_addr(which) = ((jint) ref_index<<16) | ref_kind; + void method_handle_index_at_put(int cp_index, int ref_kind, int ref_index) { + tag_at_put(cp_index, JVM_CONSTANT_MethodHandle); + *int_at_addr(cp_index) = ((jint) ref_index<<16) | ref_kind; } - void method_type_index_at_put(int which, int ref_index) { - tag_at_put(which, JVM_CONSTANT_MethodType); - *int_at_addr(which) = ref_index; + void method_type_index_at_put(int cp_index, int ref_index) { + tag_at_put(cp_index, JVM_CONSTANT_MethodType); + *int_at_addr(cp_index) = ref_index; } - void dynamic_constant_at_put(int which, int bsms_attribute_index, int name_and_type_index) { - tag_at_put(which, JVM_CONSTANT_Dynamic); - *int_at_addr(which) = ((jint) name_and_type_index<<16) | bsms_attribute_index; + void dynamic_constant_at_put(int cp_index, int bsms_attribute_index, int name_and_type_index) { + tag_at_put(cp_index, JVM_CONSTANT_Dynamic); + *int_at_addr(cp_index) = ((jint) name_and_type_index<<16) | bsms_attribute_index; } - void invoke_dynamic_at_put(int which, int bsms_attribute_index, int name_and_type_index) { - tag_at_put(which, JVM_CONSTANT_InvokeDynamic); - *int_at_addr(which) = ((jint) name_and_type_index<<16) | bsms_attribute_index; + void invoke_dynamic_at_put(int cp_index, int bsms_attribute_index, int name_and_type_index) { + tag_at_put(cp_index, JVM_CONSTANT_InvokeDynamic); + *int_at_addr(cp_index) = ((jint) name_and_type_index<<16) | bsms_attribute_index; } - void unresolved_string_at_put(int which, Symbol* s) { + void unresolved_string_at_put(int cp_index, Symbol* s) { assert(s->refcount() != 0, "should have nonzero refcount"); // Note that release_tag_at_put is not needed here because this is called only // when constructing a ConstantPool in a single thread, with no possibility // of concurrent access. - tag_at_put(which, JVM_CONSTANT_String); - *symbol_at_addr(which) = s; + tag_at_put(cp_index, JVM_CONSTANT_String); + *symbol_at_addr(cp_index) = s; } - void int_at_put(int which, jint i) { - tag_at_put(which, JVM_CONSTANT_Integer); - *int_at_addr(which) = i; + void int_at_put(int cp_index, jint i) { + tag_at_put(cp_index, JVM_CONSTANT_Integer); + *int_at_addr(cp_index) = i; } - void long_at_put(int which, jlong l) { - tag_at_put(which, JVM_CONSTANT_Long); + void long_at_put(int cp_index, jlong l) { + tag_at_put(cp_index, JVM_CONSTANT_Long); // *long_at_addr(which) = l; - Bytes::put_native_u8((address)long_at_addr(which), *((u8*) &l)); + Bytes::put_native_u8((address)long_at_addr(cp_index), *((u8*) &l)); } - void float_at_put(int which, jfloat f) { - tag_at_put(which, JVM_CONSTANT_Float); - *float_at_addr(which) = f; + void float_at_put(int cp_index, jfloat f) { + tag_at_put(cp_index, JVM_CONSTANT_Float); + *float_at_addr(cp_index) = f; } - void double_at_put(int which, jdouble d) { - tag_at_put(which, JVM_CONSTANT_Double); + void double_at_put(int cp_index, jdouble d) { + tag_at_put(cp_index, JVM_CONSTANT_Double); // *double_at_addr(which) = d; // u8 temp = *(u8*) &d; - Bytes::put_native_u8((address) double_at_addr(which), *((u8*) &d)); + Bytes::put_native_u8((address) double_at_addr(cp_index), *((u8*) &d)); } - Symbol** symbol_at_addr(int which) const { - assert(is_within_bounds(which), "index out of bounds"); - return (Symbol**) &base()[which]; + Symbol** symbol_at_addr(int cp_index) const { + assert(is_within_bounds(cp_index), "index out of bounds"); + return (Symbol**) &base()[cp_index]; } - void symbol_at_put(int which, Symbol* s) { + void symbol_at_put(int cp_index, Symbol* s) { assert(s->refcount() != 0, "should have nonzero refcount"); - tag_at_put(which, JVM_CONSTANT_Utf8); - *symbol_at_addr(which) = s; + tag_at_put(cp_index, JVM_CONSTANT_Utf8); + *symbol_at_addr(cp_index) = s; } - void string_at_put(int which, int obj_index, oop str); + void string_at_put(int obj_index, oop str); // For temporary use while constructing constant pool - void string_index_at_put(int which, int string_index) { - tag_at_put(which, JVM_CONSTANT_StringIndex); - *int_at_addr(which) = string_index; + void string_index_at_put(int cp_index, int string_index) { + tag_at_put(cp_index, JVM_CONSTANT_StringIndex); + *int_at_addr(cp_index) = string_index; } - void field_at_put(int which, int class_index, int name_and_type_index) { - tag_at_put(which, JVM_CONSTANT_Fieldref); - *int_at_addr(which) = ((jint) name_and_type_index<<16) | class_index; + void field_at_put(int cp_index, int class_index, int name_and_type_index) { + tag_at_put(cp_index, JVM_CONSTANT_Fieldref); + *int_at_addr(cp_index) = ((jint) name_and_type_index<<16) | class_index; } - void method_at_put(int which, int class_index, int name_and_type_index) { - tag_at_put(which, JVM_CONSTANT_Methodref); - *int_at_addr(which) = ((jint) name_and_type_index<<16) | class_index; + void method_at_put(int cp_index, int class_index, int name_and_type_index) { + tag_at_put(cp_index, JVM_CONSTANT_Methodref); + *int_at_addr(cp_index) = ((jint) name_and_type_index<<16) | class_index; } - void interface_method_at_put(int which, int class_index, int name_and_type_index) { - tag_at_put(which, JVM_CONSTANT_InterfaceMethodref); - *int_at_addr(which) = ((jint) name_and_type_index<<16) | class_index; // Not so nice + void interface_method_at_put(int cp_index, int class_index, int name_and_type_index) { + tag_at_put(cp_index, JVM_CONSTANT_InterfaceMethodref); + *int_at_addr(cp_index) = ((jint) name_and_type_index<<16) | class_index; // Not so nice } - void name_and_type_at_put(int which, int name_index, int signature_index) { - tag_at_put(which, JVM_CONSTANT_NameAndType); - *int_at_addr(which) = ((jint) signature_index<<16) | name_index; // Not so nice + void name_and_type_at_put(int cp_index, int name_index, int signature_index) { + tag_at_put(cp_index, JVM_CONSTANT_NameAndType); + *int_at_addr(cp_index) = ((jint) signature_index<<16) | name_index; // Not so nice } // Tag query - constantTag tag_at(int which) const { return (constantTag)tags()->at_acquire(which); } + constantTag tag_at(int cp_index) const { return (constantTag)tags()->at_acquire(cp_index); } // Fetching constants - Klass* klass_at(int which, TRAPS) { + Klass* klass_at(int cp_index, TRAPS) { constantPoolHandle h_this(THREAD, this); - return klass_at_impl(h_this, which, THREAD); + return klass_at_impl(h_this, cp_index, THREAD); } - CPKlassSlot klass_slot_at(int which) const { - assert(tag_at(which).is_unresolved_klass() || tag_at(which).is_klass(), + CPKlassSlot klass_slot_at(int cp_index) const { + assert(tag_at(cp_index).is_unresolved_klass() || tag_at(cp_index).is_klass(), "Corrupted constant pool"); - int value = *int_at_addr(which); + int value = *int_at_addr(cp_index); int name_index = extract_high_short_from_int(value); int resolved_klass_index = extract_low_short_from_int(value); return CPKlassSlot(name_index, resolved_klass_index); } - Symbol* klass_name_at(int which) const; // Returns the name, w/o resolving. - int klass_name_index_at(int which) const { - return klass_slot_at(which).name_index(); + Symbol* klass_name_at(int cp_index) const; // Returns the name, w/o resolving. + int klass_name_index_at(int cp_index) const { + return klass_slot_at(cp_index).name_index(); } - Klass* resolved_klass_at(int which) const; // Used by Compiler + Klass* resolved_klass_at(int cp_index) const; // Used by Compiler // RedefineClasses() API support: - Symbol* klass_at_noresolve(int which) { return klass_name_at(which); } - void temp_unresolved_klass_at_put(int which, int name_index) { + Symbol* klass_at_noresolve(int cp_index) { return klass_name_at(cp_index); } + void temp_unresolved_klass_at_put(int cp_index, int name_index) { // Used only during constant pool merging for class redefinition. The resolved klass index // will be initialized later by a call to initialize_unresolved_klasses(). - unresolved_klass_at_put(which, name_index, CPKlassSlot::_temp_resolved_klass_index); + unresolved_klass_at_put(cp_index, name_index, CPKlassSlot::_temp_resolved_klass_index); } - jint int_at(int which) { - assert(tag_at(which).is_int(), "Corrupted constant pool"); - return *int_at_addr(which); + jint int_at(int cp_index) { + assert(tag_at(cp_index).is_int(), "Corrupted constant pool"); + return *int_at_addr(cp_index); } - jlong long_at(int which) { - assert(tag_at(which).is_long(), "Corrupted constant pool"); - // return *long_at_addr(which); - u8 tmp = Bytes::get_native_u8((address)&base()[which]); + jlong long_at(int cp_index) { + assert(tag_at(cp_index).is_long(), "Corrupted constant pool"); + // return *long_at_addr(cp_index); + u8 tmp = Bytes::get_native_u8((address)&base()[cp_index]); return *((jlong*)&tmp); } - jfloat float_at(int which) { - assert(tag_at(which).is_float(), "Corrupted constant pool"); - return *float_at_addr(which); + jfloat float_at(int cp_index) { + assert(tag_at(cp_index).is_float(), "Corrupted constant pool"); + return *float_at_addr(cp_index); } - jdouble double_at(int which) { - assert(tag_at(which).is_double(), "Corrupted constant pool"); - u8 tmp = Bytes::get_native_u8((address)&base()[which]); + jdouble double_at(int cp_index) { + assert(tag_at(cp_index).is_double(), "Corrupted constant pool"); + u8 tmp = Bytes::get_native_u8((address)&base()[cp_index]); return *((jdouble*)&tmp); } - Symbol* symbol_at(int which) const { - assert(tag_at(which).is_utf8(), "Corrupted constant pool"); - return *symbol_at_addr(which); + Symbol* symbol_at(int cp_index) const { + assert(tag_at(cp_index).is_utf8(), "Corrupted constant pool"); + return *symbol_at_addr(cp_index); } - oop string_at(int which, int obj_index, TRAPS) { + oop string_at(int cp_index, int obj_index, TRAPS) { constantPoolHandle h_this(THREAD, this); - return string_at_impl(h_this, which, obj_index, THREAD); + return string_at_impl(h_this, cp_index, obj_index, THREAD); } - oop string_at(int which, TRAPS) { - int obj_index = cp_to_object_index(which); - return string_at(which, obj_index, THREAD); + oop string_at(int cp_index, TRAPS) { + int obj_index = cp_to_object_index(cp_index); + return string_at(cp_index, obj_index, THREAD); } // Version that can be used before string oop array is created. - oop uncached_string_at(int which, TRAPS); + oop uncached_string_at(int cp_index, TRAPS); // only called when we are sure a string entry is already resolved (via an // earlier string_at call. - oop resolved_string_at(int which) { - assert(tag_at(which).is_string(), "Corrupted constant pool"); + oop resolved_string_at(int cp_index) { + assert(tag_at(cp_index).is_string(), "Corrupted constant pool"); // Must do an acquire here in case another thread resolved the klass // behind our back, lest we later load stale values thru the oop. // we might want a volatile_obj_at in ObjArrayKlass. - int obj_index = cp_to_object_index(which); + int obj_index = cp_to_object_index(cp_index); return resolved_reference_at(obj_index); } - Symbol* unresolved_string_at(int which) { - assert(tag_at(which).is_string(), "Corrupted constant pool"); - return *symbol_at_addr(which); + Symbol* unresolved_string_at(int cp_index) { + assert(tag_at(cp_index).is_string(), "Corrupted constant pool"); + return *symbol_at_addr(cp_index); } // Returns an UTF8 for a CONSTANT_String entry at a given index. // UTF8 char* representation was chosen to avoid conversion of // java_lang_Strings at resolved entries into Symbol*s // or vice versa. - char* string_at_noresolve(int which); + char* string_at_noresolve(int cp_index); - jint name_and_type_at(int which) { - assert(tag_at(which).is_name_and_type(), "Corrupted constant pool"); - return *int_at_addr(which); + jint name_and_type_at(int cp_index) { + assert(tag_at(cp_index).is_name_and_type(), "Corrupted constant pool"); + return *int_at_addr(cp_index); } - int method_handle_ref_kind_at(int which) { - assert(tag_at(which).is_method_handle() || - tag_at(which).is_method_handle_in_error(), "Corrupted constant pool"); - return extract_low_short_from_int(*int_at_addr(which)); // mask out unwanted ref_index bits + int method_handle_ref_kind_at(int cp_index) { + assert(tag_at(cp_index).is_method_handle() || + tag_at(cp_index).is_method_handle_in_error(), "Corrupted constant pool"); + return extract_low_short_from_int(*int_at_addr(cp_index)); // mask out unwanted ref_index bits } - int method_handle_index_at(int which) { - assert(tag_at(which).is_method_handle() || - tag_at(which).is_method_handle_in_error(), "Corrupted constant pool"); - return extract_high_short_from_int(*int_at_addr(which)); // shift out unwanted ref_kind bits + int method_handle_index_at(int cp_index) { + assert(tag_at(cp_index).is_method_handle() || + tag_at(cp_index).is_method_handle_in_error(), "Corrupted constant pool"); + return extract_high_short_from_int(*int_at_addr(cp_index)); // shift out unwanted ref_kind bits } - int method_type_index_at(int which) { - assert(tag_at(which).is_method_type() || - tag_at(which).is_method_type_in_error(), "Corrupted constant pool"); - return *int_at_addr(which); + int method_type_index_at(int cp_index) { + assert(tag_at(cp_index).is_method_type() || + tag_at(cp_index).is_method_type_in_error(), "Corrupted constant pool"); + return *int_at_addr(cp_index); } // Derived queries: - Symbol* method_handle_name_ref_at(int which) { - int member = method_handle_index_at(which); + Symbol* method_handle_name_ref_at(int cp_index) { + int member = method_handle_index_at(cp_index); return uncached_name_ref_at(member); } - Symbol* method_handle_signature_ref_at(int which) { - int member = method_handle_index_at(which); + Symbol* method_handle_signature_ref_at(int cp_index) { + int member = method_handle_index_at(cp_index); return uncached_signature_ref_at(member); } - u2 method_handle_klass_index_at(int which) { - int member = method_handle_index_at(which); + u2 method_handle_klass_index_at(int cp_index) { + int member = method_handle_index_at(cp_index); return uncached_klass_ref_index_at(member); } - Symbol* method_type_signature_at(int which) { - int sym = method_type_index_at(which); + Symbol* method_type_signature_at(int cp_index) { + int sym = method_type_index_at(cp_index); return symbol_at(sym); } - u2 bootstrap_name_and_type_ref_index_at(int which) { - assert(tag_at(which).has_bootstrap(), "Corrupted constant pool"); - return extract_high_short_from_int(*int_at_addr(which)); + u2 bootstrap_name_and_type_ref_index_at(int cp_index) { + assert(tag_at(cp_index).has_bootstrap(), "Corrupted constant pool"); + return extract_high_short_from_int(*int_at_addr(cp_index)); } - u2 bootstrap_methods_attribute_index(int which) { - assert(tag_at(which).has_bootstrap(), "Corrupted constant pool"); - return extract_low_short_from_int(*int_at_addr(which)); + u2 bootstrap_methods_attribute_index(int cp_index) { + assert(tag_at(cp_index).has_bootstrap(), "Corrupted constant pool"); + return extract_low_short_from_int(*int_at_addr(cp_index)); } - int bootstrap_operand_base(int which) { - int bsms_attribute_index = bootstrap_methods_attribute_index(which); + int bootstrap_operand_base(int cp_index) { + int bsms_attribute_index = bootstrap_methods_attribute_index(cp_index); return operand_offset_at(operands(), bsms_attribute_index); } // The first part of the operands array consists of an index into the second part. @@ -563,8 +563,8 @@ class ConstantPool : public Metadata { else return operand_offset_at(operands, nextidx); } - int bootstrap_operand_limit(int which) { - int bsms_attribute_index = bootstrap_methods_attribute_index(which); + int bootstrap_operand_limit(int cp_index) { + int bsms_attribute_index = bootstrap_methods_attribute_index(cp_index); return operand_limit_at(operands(), bsms_attribute_index); } #endif //ASSERT @@ -618,22 +618,22 @@ class ConstantPool : public Metadata { // Shrink the operands array to a smaller array with new_len length void shrink_operands(int new_len, TRAPS); - u2 bootstrap_method_ref_index_at(int which) { - assert(tag_at(which).has_bootstrap(), "Corrupted constant pool"); - int op_base = bootstrap_operand_base(which); + u2 bootstrap_method_ref_index_at(int cp_index) { + assert(tag_at(cp_index).has_bootstrap(), "Corrupted constant pool"); + int op_base = bootstrap_operand_base(cp_index); return operands()->at(op_base + _indy_bsm_offset); } - u2 bootstrap_argument_count_at(int which) { - assert(tag_at(which).has_bootstrap(), "Corrupted constant pool"); - int op_base = bootstrap_operand_base(which); + u2 bootstrap_argument_count_at(int cp_index) { + assert(tag_at(cp_index).has_bootstrap(), "Corrupted constant pool"); + int op_base = bootstrap_operand_base(cp_index); u2 argc = operands()->at(op_base + _indy_argc_offset); DEBUG_ONLY(int end_offset = op_base + _indy_argv_offset + argc; - int next_offset = bootstrap_operand_limit(which)); + int next_offset = bootstrap_operand_limit(cp_index)); assert(end_offset == next_offset, "matched ending"); return argc; } - u2 bootstrap_argument_index_at(int which, int j) { - int op_base = bootstrap_operand_base(which); + u2 bootstrap_argument_index_at(int cp_index, int j) { + int op_base = bootstrap_operand_base(cp_index); DEBUG_ONLY(int argc = operands()->at(op_base + _indy_argc_offset)); assert((uint)j < (uint)argc, "oob"); return operands()->at(op_base + _indy_argv_offset + j); @@ -676,10 +676,10 @@ class ConstantPool : public Metadata { int to_cp_index(int which, Bytecodes::Code code); // Lookup for entries consisting of (name_index, signature_index) - u2 name_ref_index_at(int which_nt); // == low-order jshort of name_and_type_at(which_nt) - u2 signature_ref_index_at(int which_nt); // == high-order jshort of name_and_type_at(which_nt) + u2 name_ref_index_at(int cp_index); // == low-order jshort of name_and_type_at(cp_index) + u2 signature_ref_index_at(int cp_index); // == high-order jshort of name_and_type_at(cp_index) - BasicType basic_type_for_signature_at(int which) const; + BasicType basic_type_for_signature_at(int cp_index) const; // Resolve string constants (to prevent allocation during compilation) void resolve_string_constants(TRAPS) { @@ -701,14 +701,14 @@ class ConstantPool : public Metadata { public: // Get the tag for a constant, which may involve a constant dynamic - constantTag constant_tag_at(int which); + constantTag constant_tag_at(int cp_index); // Get the basic type for a constant, which may involve a constant dynamic - BasicType basic_type_for_constant_at(int which); + BasicType basic_type_for_constant_at(int cp_index); // Resolve late bound constants. - oop resolve_constant_at(int index, TRAPS) { + oop resolve_constant_at(int cp_index, TRAPS) { constantPoolHandle h_this(THREAD, this); - return resolve_constant_at_impl(h_this, index, _no_index_sentinel, nullptr, THREAD); + return resolve_constant_at_impl(h_this, cp_index, _no_index_sentinel, nullptr, THREAD); } oop resolve_cached_constant_at(int cache_index, TRAPS) { @@ -716,27 +716,27 @@ class ConstantPool : public Metadata { return resolve_constant_at_impl(h_this, _no_index_sentinel, cache_index, nullptr, THREAD); } - oop resolve_possibly_cached_constant_at(int pool_index, TRAPS) { + oop resolve_possibly_cached_constant_at(int cp_index, TRAPS) { constantPoolHandle h_this(THREAD, this); - return resolve_constant_at_impl(h_this, pool_index, _possible_index_sentinel, nullptr, THREAD); + return resolve_constant_at_impl(h_this, cp_index, _possible_index_sentinel, nullptr, THREAD); } - oop find_cached_constant_at(int pool_index, bool& found_it, TRAPS) { + oop find_cached_constant_at(int cp_index, bool& found_it, TRAPS) { constantPoolHandle h_this(THREAD, this); - return resolve_constant_at_impl(h_this, pool_index, _possible_index_sentinel, &found_it, THREAD); + return resolve_constant_at_impl(h_this, cp_index, _possible_index_sentinel, &found_it, THREAD); } - void copy_bootstrap_arguments_at(int index, + void copy_bootstrap_arguments_at(int cp_index, int start_arg, int end_arg, objArrayHandle info, int pos, bool must_resolve, Handle if_not_available, TRAPS) { constantPoolHandle h_this(THREAD, this); - copy_bootstrap_arguments_at_impl(h_this, index, start_arg, end_arg, + copy_bootstrap_arguments_at_impl(h_this, cp_index, start_arg, end_arg, info, pos, must_resolve, if_not_available, THREAD); } // Klass name matches name at offset - bool klass_name_at_matches(const InstanceKlass* k, int which); + bool klass_name_at_matches(const InstanceKlass* k, int cp_index); // Sizing int length() const { return _length; } @@ -791,7 +791,7 @@ class ConstantPool : public Metadata { int pre_resolve_shared_klasses(TRAPS); // Debugging - const char* printable_name_at(int which) PRODUCT_RETURN0; + const char* printable_name_at(int cp_index) PRODUCT_RETURN0; #ifdef ASSERT enum { CPCACHE_INDEX_TAG = 0x10000 }; // helps keep CP cache indices distinct from CP indices @@ -813,14 +813,14 @@ class ConstantPool : public Metadata { void set_reference_map(Array* o) { _cache->set_reference_map(o); } // Used while constructing constant pool (only by ClassFileParser) - jint klass_index_at(int which) { - assert(tag_at(which).is_klass_index(), "Corrupted constant pool"); - return *int_at_addr(which); + jint klass_index_at(int cp_index) { + assert(tag_at(cp_index).is_klass_index(), "Corrupted constant pool"); + return *int_at_addr(cp_index); } - jint string_index_at(int which) { - assert(tag_at(which).is_string_index(), "Corrupted constant pool"); - return *int_at_addr(which); + jint string_index_at(int cp_index) { + assert(tag_at(cp_index).is_string_index(), "Corrupted constant pool"); + return *int_at_addr(cp_index); } // Performs the LinkResolver checks @@ -828,23 +828,23 @@ class ConstantPool : public Metadata { // Implementation of methods that needs an exposed 'this' pointer, in order to // handle GC while executing the method - static Klass* klass_at_impl(const constantPoolHandle& this_cp, int which, TRAPS); - static oop string_at_impl(const constantPoolHandle& this_cp, int which, int obj_index, TRAPS); + static Klass* klass_at_impl(const constantPoolHandle& this_cp, int cp_index, TRAPS); + static oop string_at_impl(const constantPoolHandle& this_cp, int cp_index, int obj_index, TRAPS); static void trace_class_resolution(const constantPoolHandle& this_cp, Klass* k); // Resolve string constants (to prevent allocation during compilation) static void resolve_string_constants_impl(const constantPoolHandle& this_cp, TRAPS); - static oop resolve_constant_at_impl(const constantPoolHandle& this_cp, int index, int cache_index, + static oop resolve_constant_at_impl(const constantPoolHandle& this_cp, int cp_index, int cache_index, bool* status_return, TRAPS); - static void copy_bootstrap_arguments_at_impl(const constantPoolHandle& this_cp, int index, + static void copy_bootstrap_arguments_at_impl(const constantPoolHandle& this_cp, int cp_index, int start_arg, int end_arg, objArrayHandle info, int pos, bool must_resolve, Handle if_not_available, TRAPS); // Exception handling - static void save_and_throw_exception(const constantPoolHandle& this_cp, int which, constantTag tag, TRAPS); + static void save_and_throw_exception(const constantPoolHandle& this_cp, int cp_index, constantTag tag, TRAPS); public: // Exception handling @@ -852,12 +852,12 @@ class ConstantPool : public Metadata { // Merging ConstantPool* support: bool compare_entry_to(int index1, const constantPoolHandle& cp2, int index2); - void copy_cp_to(int start_i, int end_i, const constantPoolHandle& to_cp, int to_i, TRAPS) { + void copy_cp_to(int start_cpi, int end_cpi, const constantPoolHandle& to_cp, int to_cpi, TRAPS) { constantPoolHandle h_this(THREAD, this); - copy_cp_to_impl(h_this, start_i, end_i, to_cp, to_i, THREAD); + copy_cp_to_impl(h_this, start_cpi, end_cpi, to_cp, to_cpi, THREAD); } - static void copy_cp_to_impl(const constantPoolHandle& from_cp, int start_i, int end_i, const constantPoolHandle& to_cp, int to_i, TRAPS); - static void copy_entry_to(const constantPoolHandle& from_cp, int from_i, const constantPoolHandle& to_cp, int to_i); + static void copy_cp_to_impl(const constantPoolHandle& from_cp, int start_cpi, int end_cpi, const constantPoolHandle& to_cp, int to_cpi, TRAPS); + static void copy_entry_to(const constantPoolHandle& from_cp, int from_cpi, const constantPoolHandle& to_cp, int to_cpi); static void copy_operands(const constantPoolHandle& from_cp, const constantPoolHandle& to_cp, TRAPS); int find_matching_entry(int pattern_i, const constantPoolHandle& search_cp); int version() const { return _saved._version; } From 0a3c6d6bd010231d02e92016037149e85fb1db3f Mon Sep 17 00:00:00 2001 From: Tejesh R Date: Tue, 1 Aug 2023 04:28:42 +0000 Subject: [PATCH 11/11] 8280482: Window transparency bug on Linux Reviewed-by: dnguyen, azvegint --- .../unix/classes/sun/awt/X11/XWindowPeer.java | 6 +- .../MultiScreenCheckScreenIDTest.java | 148 ++++++++++++++++++ 2 files changed, 151 insertions(+), 3 deletions(-) create mode 100644 test/jdk/java/awt/Multiscreen/MultiScreenCheckScreenIDTest.java diff --git a/src/java.desktop/unix/classes/sun/awt/X11/XWindowPeer.java b/src/java.desktop/unix/classes/sun/awt/X11/XWindowPeer.java index 02f5aaaa816..9509c5a153b 100644 --- a/src/java.desktop/unix/classes/sun/awt/X11/XWindowPeer.java +++ b/src/java.desktop/unix/classes/sun/awt/X11/XWindowPeer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2023, 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 @@ -804,10 +804,10 @@ public void handleConfigureNotifyEvent(XEvent xev) { if (insLog.isLoggable(PlatformLogger.Level.FINE)) { insLog.fine(xe.toString()); } - checkIfOnNewScreen(toGlobal(new Rectangle(scaleDown(xe.get_x()), + checkIfOnNewScreen(new Rectangle(scaleDown(xe.get_x()), scaleDown(xe.get_y()), scaleDown(xe.get_width()), - scaleDown(xe.get_height())))); + scaleDown(xe.get_height()))); Rectangle oldBounds = getBounds(); diff --git a/test/jdk/java/awt/Multiscreen/MultiScreenCheckScreenIDTest.java b/test/jdk/java/awt/Multiscreen/MultiScreenCheckScreenIDTest.java new file mode 100644 index 00000000000..14717da5790 --- /dev/null +++ b/test/jdk/java/awt/Multiscreen/MultiScreenCheckScreenIDTest.java @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2023, 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. + */ + +import java.awt.AWTException; +import java.awt.Color; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.Window; + +import javax.swing.JWindow; +import javax.swing.SwingUtilities; + +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.List; + +/* + * @test + * @bug 8280482 + * @key headful + * @summary Test to check if window GC doesn't change within same screen. + * @run main MultiScreenCheckScreenIDTest + */ + +public class MultiScreenCheckScreenIDTest extends MouseAdapter { + private static final int COLS = 12; + private static final int ROWS = 8; + private static final Color BACKGROUND = new Color(0, 0, 255, 64); + private static GraphicsDevice[] screens; + static List windowList = new ArrayList<>(); + static Robot robot; + static JWindow window; + + + public static void main(final String[] args) throws Exception { + try { + createGUI(); + } finally { + for (Window win : windowList) { + win.dispose(); + } + if (window != null) { + window.dispose(); + } + } + System.out.println("Test Pass"); + } + + private static void createGUI() throws AWTException { + new MultiScreenCheckScreenIDTest().createWindowGrid(); + } + + private void createWindowGrid() throws AWTException { + screens = GraphicsEnvironment + .getLocalGraphicsEnvironment() + .getScreenDevices(); + + if (screens.length < 2) { + System.out.println("Testing aborted. Required min of 2 screens. " + + "Available : " + screens.length); + return; + } + robot = new Robot(); + + int screenNumber = 1; + for (GraphicsDevice screen : screens) { + Rectangle screenBounds = screen.getDefaultConfiguration().getBounds(); + + for (Rectangle r : gridOfRectangles(screenBounds, COLS, ROWS)) { + try { + SwingUtilities.invokeAndWait(() -> { + try { + window = createWindow(r); + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + } catch (InterruptedException | InvocationTargetException e) { + e.printStackTrace(); + } + robot.delay(50); + robot.waitForIdle(); + if (window.getBounds().intersects(screenBounds)) { + if (!(window.getGraphicsConfiguration().getBounds(). + intersects(screenBounds))) { + throw new RuntimeException("Graphics configuration " + + "changed for screen :" + screenNumber); + } + } + windowList.add(window); + } + screenNumber++; + } + } + + private JWindow createWindow(Rectangle bounds) { + JWindow window = new JWindow(); + window.setBounds(bounds); + window.setBackground(BACKGROUND); + window.setAlwaysOnTop(true); + window.addMouseListener(this); + window.setVisible(true); + return window; + } + + @Override + public void mouseClicked(MouseEvent e) { + ((Window) e.getSource()).dispose(); + } + + private static List gridOfRectangles(Rectangle r, int cols, int rows) { + List l = new ArrayList<>(); + for (int row = 0; row < rows; row++) { + int y1 = r.y + (int) Math.round(r.height * (double) row / rows); + int y2 = r.y + (int) Math.round(r.height * (double) (row + 1) / rows); + for (int col = 0; col < cols; col++) { + int x1 = r.x + (int) Math.round(r.width * (double) col / cols); + int x2 = r.x + (int) Math.round(r.width * (double) (col + 1) / cols); + l.add(new Rectangle(x1, y1, x2 - x1, y2 - y1)); + } + } + return l; + } +}