From 05c2b6cd47c68d96dcb7b3db594a334e05c6ee36 Mon Sep 17 00:00:00 2001 From: Ashutosh Mehra Date: Thu, 29 Jun 2023 14:16:15 +0000 Subject: [PATCH] 8309979: BootstrapMethods attribute is missing in class files recreated by SA Reviewed-by: cjplummer, kevinw --- .../sun/jvm/hotspot/oops/ConstantPool.java | 69 ++++++++++++++++--- .../sun/jvm/hotspot/oops/InstanceKlass.java | 1 - .../jvm/hotspot/tools/jcore/ClassWriter.java | 30 ++++++++ 3 files changed, 91 insertions(+), 9 deletions(-) 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 ec6940466d9..cec1849cf7b 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 @@ -130,7 +130,10 @@ public class ConstantPool extends Metadata implements ClassConstants { private static int INDY_ARGV_OFFSET; public U1Array getTags() { return new U1Array(tags.getValue(getAddress())); } - public U2Array getOperands() { return new U2Array(operands.getValue(getAddress())); } + public U2Array getOperands() { + Address addr = operands.getValue(getAddress()); + return VMObjectFactory.newObject(U2Array.class, addr); + } public ConstantPoolCache getCache() { Address addr = cache.getValue(getAddress()); return VMObjectFactory.newObject(ConstantPoolCache.class, addr); @@ -464,16 +467,50 @@ public class ConstantPool extends Metadata implements ClassConstants { return res; } - /** Lookup for multi-operand (InvokeDynamic, Dynamic) entries. */ - public short[] getBootstrapSpecifierAt(int i) { - if (Assert.ASSERTS_ENABLED) { - Assert.that(getTagAt(i).isInvokeDynamic() || getTagAt(i).isDynamicConstant(), "Corrupted constant pool"); + public int getBootstrapMethodsCount() { + U2Array operands = getOperands(); + int count = 0; + if (operands != null) { + // Operands array consists of two parts. First part is an array of 32-bit values which denote + // index of the bootstrap method data in the operands array. Note that elements of operands array are of type short. + // So each element of first part occupies two slots in the array. + // Second part is the bootstrap methods data. + // This layout allows us to get BSM count by getting the index of first BSM and dividing it by 2. + // + // The example below shows layout of operands array with 3 bootstrap methods. + // First part has 3 32-bit values indicating the index of the respective bootstrap methods in + // the operands array. + // The first BSM is at index 6. So the count in this case is 6/2=3. + // + // <-----first part----><-------second part-------> + // index: 0 2 4 6 i2 i3 + // operands: | 6 | i2 | i3 | bsm1 | bsm2 | bsm3 | + // + count = getOperandOffsetAt(operands, 0) / 2; } - int bsmSpec = extractLowShortFromInt(this.getIntAt(i)); + if (DEBUG) { + System.err.println("ConstantPool.getBootstrapMethodsCount: count = " + count); + } + return count; + } + + public int getBootstrapMethodArgsCount(int bsmIndex) { + U2Array operands = getOperands(); + if (Assert.ASSERTS_ENABLED) { + Assert.that(operands != null, "Operands is not present"); + } + int bsmOffset = getOperandOffsetAt(operands, bsmIndex); + int argc = operands.at(bsmOffset + INDY_ARGC_OFFSET); + if (DEBUG) { + System.err.println("ConstantPool.getBootstrapMethodArgsCount: bsm index = " + bsmIndex + ", args count = " + argc); + } + return argc; + } + + public short[] getBootstrapMethodAt(int bsmIndex) { U2Array operands = getOperands(); if (operands == null) return null; // safety first - int basePos = VM.getVM().buildIntFromShorts(operands.at(bsmSpec * 2 + 0), - operands.at(bsmSpec * 2 + 1)); + int basePos = getOperandOffsetAt(operands, bsmIndex); int argv = basePos + INDY_ARGV_OFFSET; int argc = operands.at(basePos + INDY_ARGC_OFFSET); int endPos = argv + argc; @@ -484,6 +521,15 @@ public class ConstantPool extends Metadata implements ClassConstants { return values; } + /** Lookup for multi-operand (InvokeDynamic, Dynamic) entries. */ + public short[] getBootstrapSpecifierAt(int i) { + if (Assert.ASSERTS_ENABLED) { + Assert.that(getTagAt(i).isInvokeDynamic() || getTagAt(i).isDynamicConstant(), "Corrupted constant pool"); + } + int bsmSpec = extractLowShortFromInt(this.getIntAt(i)); + return getBootstrapMethodAt(bsmSpec); + } + private static final String[] nameForTag = new String[] { }; @@ -756,4 +802,11 @@ public class ConstantPool extends Metadata implements ClassConstants { // must stay in sync with ConstantPool::name_and_type_at_put, method_at_put, etc. return val & 0xFFFF; } + + // Return the offset of the requested Bootstrap Method in the operands array + private int getOperandOffsetAt(U2Array operands, int bsmIndex) { + return VM.getVM().buildIntFromShorts(operands.at(bsmIndex * 2), + operands.at(bsmIndex * 2 + 1)); + } + } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java index 2c3f2d2a698..06eac193933 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java @@ -859,7 +859,6 @@ public class InstanceKlass extends Klass { return VMObjectFactory.newObject(U2Array.class, addr); } - //---------------------------------------------------------------------- // Internals only below this point // diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/jcore/ClassWriter.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/jcore/ClassWriter.java index fa8af4d463c..5dfa7eec30a 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/jcore/ClassWriter.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/jcore/ClassWriter.java @@ -61,6 +61,7 @@ public class ClassWriter implements /* imports */ ClassConstants protected short _lineNumberTableIndex; protected short _localVariableTableIndex; protected short _signatureIndex; + protected short _bootstrapMethodsIndex; protected static int extractHighShortFromInt(int val) { // must stay in sync with ConstantPool::name_and_type_at_put, method_at_put, etc. @@ -142,6 +143,8 @@ public class ClassWriter implements /* imports */ ClassConstants _innerClassesIndex = (innerClassesIndex != null)? innerClassesIndex.shortValue() : 0; if (DEBUG) debugMessage("InnerClasses index = " + _innerClassesIndex); + Short bootstrapMethodsIndex = utf8ToIndex.get("BootstrapMethods"); + _bootstrapMethodsIndex = (bootstrapMethodsIndex != null) ? bootstrapMethodsIndex.shortValue() : 0; // field attributes Short constantValueIndex = utf8ToIndex.get("ConstantValue"); _constantValueIndex = (constantValueIndex != null)? @@ -723,6 +726,11 @@ public class ClassWriter implements /* imports */ ClassConstants if (numInnerClasses != 0) classAttributeCount++; + int bsmCount = klass.getConstants().getBootstrapMethodsCount(); + if (bsmCount != 0) { + classAttributeCount++; + } + dos.writeShort(classAttributeCount); if (DEBUG) debugMessage("class attribute count = " + classAttributeCount); @@ -762,5 +770,27 @@ public class ClassWriter implements /* imports */ ClassConstants dos.writeShort(innerClasses.at(index)); } } + + // write bootstrap method attribute, if any + if (bsmCount != 0) { + ConstantPool cpool = klass.getConstants(); + writeIndex(_bootstrapMethodsIndex); + if (DEBUG) debugMessage("bootstrap methods attribute = " + _bootstrapMethodsIndex); + int attrLen = 2; // num_bootstrap_methods + for (int index = 0; index < bsmCount; index++) { + int bsmArgsCount = cpool.getBootstrapMethodArgsCount(index); + attrLen += 2 // bootstrap_method_ref + + 2 // num_bootstrap_arguments + + bsmArgsCount * 2; + } + dos.writeInt(attrLen); + dos.writeShort(bsmCount); + for (int index = 0; index < bsmCount; index++) { + short value[] = cpool.getBootstrapMethodAt(index); + for (int i = 0; i < value.length; i++) { + dos.writeShort(value[i]); + } + } + } } }