JDK-8209899 : [lworld] dcmd tests crash with "Unexpected constant pool layout"
  • Type: Bug
  • Component: hotspot
  • Sub-Component: runtime
  • Affected Version: repo-valhalla
  • Priority: P4
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2018-08-23
  • Updated: 2018-09-07
  • Resolved: 2018-09-07
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
repo-valhallaFixed
Related Reports
Relates :  
Relates :  
Relates :  
Description
These three JTReg tests fail with similar assertion and stack traces:

serviceability/dcmd/vm/ShowReflectionTargetTest.java
serviceability/dcmd/vm/ClassLoaderHierarchyTest.java
serviceability/dcmd/vm/ClassHierarchyTest.java

Assert and stack trace:

#  Internal Error (.../src/hotspot/share/oops/reflectionAccessorImplKlassHelper.cpp:79), pid=67127, tid=67136
#  assert(cp->tag_at(cpi).is_utf8()) failed: Unexpected constant pool layout for "jdk.internal.reflect.GeneratedConstructorAccessor20", child class of Generated{Method|Constructor}AccessorImplXXX (no UTF8 at cpi 8 (7)).

Current thread (0x00007fc790664800):  VMThread "VM Thread" [stack: 0x00007fc7221eb000,0x00007fc7222eb000] [id=67136]

Stack: [0x00007fc7221eb000,0x00007fc7222eb000],  sp=0x00007fc7222e9500,  free space=1017k
Native frames: (J=compiled Java code, A=aot compiled Java code, j=interpreted, Vv=VM code, C=native code)
V  [libjvm.so+0x18f8417]  VMError::report_and_die(int, char const*, char const*, __va_list_tag*, Thread*, unsigned char*, void*, void*, char const*, int, unsigned long)+0x2c7
V  [libjvm.so+0x18f927f]  VMError::report_and_die(Thread*, void*, char const*, int, char const*, char const*, __va_list_tag*)+0x2f
V  [libjvm.so+0xb34820]  report_vm_error(char const*, int, char const*, char const*, ...)+0x100
V  [libjvm.so+0x1616c4e]  get_string_from_cp_with_checks(InstanceKlass const*, int)+0x1ee
V  [libjvm.so+0x1617978]  ReflectionAccessorImplKlassHelper::print_invocation_target(outputStream*, Klass*)+0x198
V  [libjvm.so+0xe0ee9d]  KlassHierarchy::print_class(outputStream*, KlassInfoEntry*, bool)+0x43d
V  [libjvm.so+0xe119a1]  KlassHierarchy::print_class_hierarchy(outputStream*, bool, bool, char*)+0x601
V  [libjvm.so+0x193b8a2]  VM_Operation::evaluate()+0x132
V  [libjvm.so+0x1936fce]  VMThread::evaluate_operation(VM_Operation*) [clone .constprop.46]+0x18e
V  [libjvm.so+0x1937870]  VMThread::loop()+0x4c0
V  [libjvm.so+0x1937e63]  VMThread::run()+0xd3
V  [libjvm.so+0x14dc620]  thread_native_entry(Thread*)+0x100

VM_Operation (0x00007fc7213b61e0): PrintClassHierarchy, mode: safepoint, requested by thread 0x00007fc7908b6800

The problem occurs with and without EnableValhalla

Comments
Thanks to Mandy for the changes to MethodAccessorGenerator.java! Changeset: 01fc0d30437a Author: hseigel Date: 2018-09-07 13:09 -0400 URL: http://hg.openjdk.java.net/valhalla/valhalla/rev/01fc0d30437a 8209899: [lworld] dcmd tests crash with "Unexpected constant pool layout" Summary: Generate constant pool ValueType attribute entries after the fields depended on by jcmd. Reviewed-by: mchung ! src/java.base/share/classes/jdk/internal/reflect/MethodAccessorGenerator.java ! test/hotspot/jtreg/ProblemList.txt ! test/jdk/ProblemList.txt
07-09-2018

Below is my suggested patch. This will emit CP entries lazily and when the index is obtained. This should generate top few CP entries in the same position. It's too fragile to hardcode the CP entry indices. I suggest to file a JBS issue to look into eliminating the hardcoded dependency to CP indices from dcmd. diff --git a/src/java.base/share/classes/jdk/internal/reflect/MethodAccessorGenerator.java b/src/java.base/share/classes/jdk/internal/reflect/MethodAccessorGenerator.java --- a/src/java.base/share/classes/jdk/internal/reflect/MethodAccessorGenerator.java +++ b/src/java.base/share/classes/jdk/internal/reflect/MethodAccessorGenerator.java @@ -159,6 +159,12 @@ // [CONSTANT_Class_info] for above // [UTF-8] [Target class's name] // [CONSTANT_Class_info] for above + // ^ [UTF-8] [Serialization: Class's name in which to invoke constructor] + // ^ [CONSTANT_Class_info] for above + // [UTF-8] target method or constructor name + // [UTF-8] target method or constructor signature + // [CONSTANT_NameAndType_info] for above + // [CONSTANT_Methodref_info or CONSTANT_InterfaceMethodref_info] for target method // [UTF-8] descriptor for type of non-primitive parameter 1 // [CONSTANT_Class_info] for type of non-primitive parameter 1 // ... @@ -167,12 +173,6 @@ // [UTF-8] descriptor for declared value types if not present in CP // [CONSTANT_Class_info] for declared value types if not present in CP // ... - // ^ [UTF-8] [Serialization: Class's name in which to invoke constructor] - // ^ [CONSTANT_Class_info] for above - // [UTF-8] target method or constructor name - // [UTF-8] target method or constructor signature - // [CONSTANT_NameAndType_info] for above - // [CONSTANT_Methodref_info or CONSTANT_InterfaceMethodref_info] for target method // [UTF-8] "invoke" or "newInstance" // [UTF-8] invoke or newInstance descriptor // + [UTF-8] "java/lang/Exception" @@ -312,11 +312,7 @@ } asm.emitConstantPoolClass(asm.cpi()); superClass = asm.cpi(); - - // emit constant pool entries for declaring class, parameter types and return type - cpClassPool.emitConstantPoolEntries(); targetClass = cpClassPool.cpIndex(declaringClass); - short serializationTargetClassIdx = (short) 0; if (forSerialization) { asm.emitConstantPoolUTF8(getClassName(serializationTargetClass, false)); @@ -336,6 +332,10 @@ } } targetMethodRef = asm.cpi(); + + // emit constant pool entries for parameter types and return type + cpClassPool.emitConstantPoolEntries(); + if (isConstructor) { asm.emitConstantPoolUTF8("newInstance"); } else { @@ -841,7 +841,7 @@ void emitConstantPoolEntries() { for (Class<?> c : types) { - cpEntries.put(c, emitConstantPoolEntries(c)); + cpEntries.computeIfAbsent(c, this::emitConstantPoolEntries); } } @@ -856,7 +856,7 @@ } short cpIndex(Class<?> c) { - return cpEntries.get(c); + return cpEntries.computeIfAbsent(c, this::emitConstantPoolEntries); } short[] declaredValueTypes() {
06-09-2018

Is it possible to move the ValueTypes attribute related constant pool entries after the target method name and signature? Something like: diff --git a/src/java.base/share/classes/jdk/internal/reflect/MethodAccessorGenerator.java b/src/java.base/share/classes/jdk/internal/reflect/MethodAccessorGenerator.java --- a/src/java.base/share/classes/jdk/internal/reflect/MethodAccessorGenerator.java +++ b/src/java.base/share/classes/jdk/internal/reflect/MethodAccessorGenerator.java @@ -278,7 +278,7 @@ // * [CONSTANT_NameAndType_info] for above // * [CONSTANT_Methodref_info] for above - short numCPEntries = NUM_BASE_CPOOL_ENTRIES + NUM_COMMON_CPOOL_ENTRIES; + short numCPEntries = NUM_BASE_CPOOL_ENTRIES + NUM_COMMON_CPOOL_ENTRIES + 2; boolean usesPrimitives = usesPrimitiveTypes(); if (usesPrimitives) { numCPEntries += NUM_BOXING_CPOOL_ENTRIES; @@ -313,9 +313,9 @@ asm.emitConstantPoolClass(asm.cpi()); superClass = asm.cpi(); - // emit constant pool entries for declaring class, parameter types and return type - cpClassPool.emitConstantPoolEntries(); - targetClass = cpClassPool.cpIndex(declaringClass); + asm.emitConstantPoolUTF8(getClassName(declaringClass, false)); + asm.emitConstantPoolClass(asm.cpi()); + targetClass = asm.cpi(); short serializationTargetClassIdx = (short) 0; if (forSerialization) { @@ -350,6 +350,9 @@ } invokeDescriptorIdx = asm.cpi(); + // emit constant pool entries for declaring class, parameter types and return type + cpClassPool.emitConstantPoolEntries(); + // emit name index for "ValueTypes" attribute if (cpClassPool.hasDeclaredValueTypes()) { asm.emitConstantPoolUTF8("ValueTypes");
31-08-2018

It's not a good idea to hard code the index to the constant pools to look for the specific names such as target method name and signature. The generated class file is subject to change. In lworld the constant pool entries for the parameter types, return type, and types listed in value types attributes are emitted before the target method name and signature whose CP index is not a fixed location.
31-08-2018

reflectionAccessorImplKlassHelper.cpp expects constant pools to contain the following format. In particular, for classes that are not SerializationConstructorAccessors, it expects the method name and signature to be in constant pool slots 7 and 8. This comment is from reflectionAccessorImplKlassHelper.cpp: // We extract target class name, method name and sig from the constant pool of the Accessor class. // This is an excerpt of the Constant pool (see jdk/internal/reflect/MethodAccessorGenerator.java:) // (^ = Only present if generating SerializationConstructorAccessor) // 1 [UTF-8] [This class's name] // 2 [CONSTANT_Class_info] for above // 3 [UTF-8] "jdk/internal/reflect/{MethodAccessorImpl,ConstructorAccessorImpl,SerializationConstructorAccessorImpl}" // 4 [CONSTANT_Class_info] for above // 5 [UTF-8] [Target class's name] // 6 [CONSTANT_Class_info] for above // 7^ [UTF-8] [Serialization: Class's name in which to invoke constructor] // 8^ [CONSTANT_Class_info] for above // 9 [UTF-8] target method or constructor name // 10 [UTF-8] target method or constructor signature But, this has changed in lworld. Class java.base/share/classes/jdk/internal/reflect/MethodAccessorGenerator.java in lworld has the following comment explaining the new constant pool entry line-up. // Constant pool entries: // ( * = Boxing information: optional) // (+ = Shared entries provided by AccessorGenerator) // (^ = Only present if generating SerializationConstructorAccessor) // [UTF-8] [This class's name] // [CONSTANT_Class_info] for above // [UTF-8] "jdk/internal/reflect/{MethodAccessorImpl,ConstructorAccessorImpl,SerializationConstructorAccessorImpl}" // [CONSTANT_Class_info] for above // [UTF-8] [Target class's name] // [CONSTANT_Class_info] for above // [UTF-8] descriptor for type of non-primitive parameter 1 // [CONSTANT_Class_info] for type of non-primitive parameter 1 // ... // [UTF-8] descriptor for type of non-primitive parameter n // [CONSTANT_Class_info] for type of non-primitive parameter n // [UTF-8] descriptor for declared value types if not present in CP // [CONSTANT_Class_info] for declared value types if not present in CP // ... // ^ [UTF-8] [Serialization: Class's name in which to invoke constructor] // ^ [CONSTANT_Class_info] for above // [UTF-8] target method or constructor name // [UTF-8] target method or constructor signature
30-08-2018