Skip to content

Commit 424607a

Browse files
Record support (#520)
* Implemented parsing for the record * Added support for printing record components * Implemented RecordComponentInfo class to hold record metadata * Updated ClassInfo.java to support record functionality * Added support for parsing record components like name,descriptor and annotation attributes
1 parent fc3fbfe commit 424607a

File tree

7 files changed

+260
-3
lines changed

7 files changed

+260
-3
lines changed

src/main/gov/nasa/jpf/jvm/ClassFile.java

Lines changed: 80 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ public String getRequestedTypeName(){
178178
public static final String RUNTIME_INVISIBLE_ANNOTATIONS_ATTR = "RuntimeInvisibleAnnotations";
179179
public static final String RUNTIME_VISIBLE_ANNOTATIONS_ATTR = "RuntimeVisibleAnnotations";
180180
public static final String RUNTIME_VISIBLE_TYPE_ANNOTATIONS_ATTR = "RuntimeVisibleTypeAnnotations";
181+
public static final String RUNTIME_INVISIBLE_TYPE_ANNOTATIONS_ATTR = "RuntimeInvisibleTypeAnnotations";
181182

182183
//--- standard field attributes
183184
public static final String CONST_VALUE_ATTR = "ConstantValue";
@@ -216,11 +217,19 @@ public String getRequestedTypeName(){
216217
public static final String INNER_CLASSES_ATTR = "InnerClasses";
217218
public static final String ENCLOSING_METHOD_ATTR = "EnclosingMethod";
218219
public static final String BOOTSTRAP_METHOD_ATTR = "BootstrapMethods";
219-
220+
public static final String RECORD_ATTR = "Record";
221+
220222
protected final static String[] stdClassAttrs = {
221223
SOURCE_FILE_ATTR, DEPRECATED_ATTR, INNER_CLASSES_ATTR, DEPRECATED_ATTR, SIGNATURE_ATTR,
222224
RUNTIME_INVISIBLE_ANNOTATIONS_ATTR, RUNTIME_VISIBLE_ANNOTATIONS_ATTR, RUNTIME_VISIBLE_TYPE_ANNOTATIONS_ATTR,
223-
ENCLOSING_METHOD_ATTR, BOOTSTRAP_METHOD_ATTR };
225+
ENCLOSING_METHOD_ATTR, BOOTSTRAP_METHOD_ATTR, RECORD_ATTR};
226+
227+
//--- standard Record attributes
228+
public static final String[] stdRecordComponentAttrs = {
229+
SIGNATURE_ATTR,
230+
RUNTIME_INVISIBLE_ANNOTATIONS_ATTR, RUNTIME_VISIBLE_ANNOTATIONS_ATTR,
231+
RUNTIME_INVISIBLE_TYPE_ANNOTATIONS_ATTR, RUNTIME_VISIBLE_TYPE_ANNOTATIONS_ATTR
232+
};
224233

225234

226235
protected String internStdAttrName(int cpIdx, String name, String[] stdNames){
@@ -1530,6 +1539,75 @@ public void parseBootstrapMethodAttr (ClassFileReader reader, Object tag){
15301539

15311540
setBootstrapMethodsDone( reader, tag);
15321541
}
1542+
1543+
//-- record parsing
1544+
/*
1545+
Record_attribute {
1546+
u2 attribute_name_index;
1547+
u4 attribute_length;
1548+
u2 components_count;
1549+
{
1550+
u2 name_index;
1551+
u2 descriptor_index;
1552+
u2 attributes_count;
1553+
attribute_info attributes[attributes_count];
1554+
} components[components_count];
1555+
}
1556+
*/
1557+
private void setRecordComponentCount(ClassFileReader reader, Object tag, int count) {
1558+
int p = pos;
1559+
reader.setRecordComponentCount(this, tag, count);
1560+
pos = p;
1561+
}
1562+
1563+
private void setRecordComponent(ClassFileReader reader, Object tag, int index, String name, String descriptor, int attributesCount) {
1564+
int p = pos;
1565+
reader.setRecordComponent(this, tag, index, name, descriptor, attributesCount);
1566+
pos = p;
1567+
}
1568+
1569+
private void setRecordComponentAttribute(ClassFileReader reader, Object tag, int componentIndex, int attrIndex, String attrName, int attrLength) {
1570+
int p = pos + attrLength;
1571+
reader.setRecordComponentAttribute(this, tag, componentIndex, attrIndex, attrName, attrLength);
1572+
pos = p;
1573+
}
1574+
1575+
private void setRecordComponentsDone(ClassFileReader reader, Object tag) {
1576+
int p = pos;
1577+
reader.setRecordComponentsDone(this, tag);
1578+
pos = p;
1579+
}
1580+
1581+
public void parseRecordAttribute(ClassFileReader reader, Object tag) {
1582+
int componentsCount = readU2();
1583+
setRecordComponentCount(reader, tag, componentsCount);
1584+
1585+
for (int i = 0; i < componentsCount; i++) {
1586+
int nameIndex = readU2();
1587+
String name = utf8At(nameIndex);
1588+
1589+
int descriptorIndex = readU2();
1590+
String descriptor = utf8At(descriptorIndex);
1591+
1592+
int attributesCount = readU2();
1593+
1594+
// Create and set the record component
1595+
setRecordComponent(reader, tag, i, name, descriptor, attributesCount);
1596+
1597+
// Parse the component attributes
1598+
for (int j = 0; j < attributesCount; j++) {
1599+
int attrNameIndex = readU2();
1600+
String attrName = utf8At(attrNameIndex);
1601+
1602+
attrName = internStdAttrName(attrNameIndex, attrName, stdRecordComponentAttrs);
1603+
1604+
int attrLength = readI4();
1605+
setRecordComponentAttribute(reader, tag, i, j, attrName, attrLength);
1606+
}
1607+
}
1608+
1609+
setRecordComponentsDone(reader, tag);
1610+
}
15331611

15341612
String nameAt(int nameTypeInfoIdx) {
15351613
return utf8At(u2(cpPos[nameTypeInfoIdx] + 1));

src/main/gov/nasa/jpf/jvm/ClassFilePrinter.java

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,47 @@ public void setMethodAttribute(ClassFile cf, int methodIndex, int attrIndex, Str
188188
}
189189
}
190190

191+
//--- records
192+
@Override
193+
public void setRecordComponentCount(ClassFile cf, Object tag, int count) {
194+
printSectionHeader("record components");
195+
pw.printf("%srecord component count=%d\n", indent, count);
196+
incIndent();
197+
}
198+
199+
@Override
200+
public void setRecordComponent(ClassFile cf, Object tag, int index, String name, String descriptor, int attributesCount) {
201+
pw.printf("%s[%d]: %s, type=%s", indent, index, name, descriptor);
202+
}
203+
204+
@Override
205+
public void setRecordComponentAttribute(ClassFile cf, Object tag, int componentIndex, int attrIndex, String attrName, int attrLength) {
206+
pw.printf(", attribute[%d]: %s", attrIndex, attrName);
207+
208+
if (attrName == ClassFile.SIGNATURE_ATTR) {
209+
cf.parseSignatureAttr(this, tag);
210+
} else if (attrName == ClassFile.RUNTIME_VISIBLE_ANNOTATIONS_ATTR) {
211+
cf.parseAnnotationsAttr(this, tag);
212+
} else if (attrName == ClassFile.RUNTIME_INVISIBLE_ANNOTATIONS_ATTR) {
213+
cf.parseAnnotationsAttr(this, tag);
214+
} else if (attrName == ClassFile.RUNTIME_VISIBLE_TYPE_ANNOTATIONS_ATTR) {
215+
cf.parseTypeAnnotationsAttr(this, tag);
216+
} else if (attrName == ClassFile.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS_ATTR) {
217+
cf.parseTypeAnnotationsAttr(this, tag);
218+
} else {
219+
pw.printf(" ,length=%d,data=[", attrLength);
220+
printRawData(pw, cf, attrLength, 10);
221+
pw.println(']');
222+
}
223+
224+
pw.println();
225+
}
226+
227+
@Override
228+
public void setRecordComponentsDone(ClassFile cf, Object tag) {
229+
decIndent();
230+
}
231+
191232
@Override
192233
public void setMethodAttributesDone(ClassFile cf, int methodIndex){
193234
decIndent();

src/main/gov/nasa/jpf/jvm/ClassFileReader.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,4 +195,13 @@ void setEnumAnnotationValue(ClassFile cf, Object tag, int annotationIndex, int v
195195

196196

197197
void setSignature(ClassFile cf, Object tag, String signature);
198+
199+
//--- records
200+
void setRecordComponentCount(ClassFile cf, Object tag, int count);
201+
202+
void setRecordComponent(ClassFile cf, Object tag, int index, String name, String descriptor, int attributesCount);
203+
204+
void setRecordComponentAttribute(ClassFile cf, Object tag, int componentIndex, int attrIndex, String attrName, int attrLength);
205+
206+
void setRecordComponentsDone(ClassFile cf, Object tag);
198207
}

src/main/gov/nasa/jpf/jvm/ClassFileReaderAdapter.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,4 +249,16 @@ public void setSignature(ClassFile cf, Object tag, String signature) {}
249249

250250
@Override
251251
public void setAnnotationFieldValue(ClassFile cf, Object tag, int annotationIndex, int valueIndex, String elementName, int arrayIndex) {}
252+
253+
@Override
254+
public void setRecordComponentCount(ClassFile cf, Object tag, int count) {}
255+
256+
@Override
257+
public void setRecordComponent(ClassFile cf, Object tag, int index, String name, String descriptor, int attributesCount) {}
258+
259+
@Override
260+
public void setRecordComponentAttribute(ClassFile cf, Object tag, int componentIndex, int attrIndex, String attrName, int attrLength) {}
261+
262+
@Override
263+
public void setRecordComponentsDone(ClassFile cf, Object tag) {}
252264
}

src/main/gov/nasa/jpf/jvm/JVMClassInfo.java

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,9 @@ public void setClassAttribute (ClassFile cf, int attrIndex, String name, int att
8484
} else if (name == ClassFile.BOOTSTRAP_METHOD_ATTR) {
8585
cf.parseBootstrapMethodAttr(this, JVMClassInfo.this);
8686

87+
} else if (name == ClassFile.RECORD_ATTR){
88+
cf.parseRecordAttribute(this,JVMClassInfo.this);
89+
8790
}
8891
}
8992

@@ -189,6 +192,65 @@ public void setBootstrapMethodInfo(ClassInfo enclosingCls, String mthName, Strin
189192
}
190193
}
191194

195+
//--- Storing record while parsing
196+
@Override
197+
public void setRecordComponentCount(ClassFile cf, Object tag, int count) {
198+
JVMClassInfo.this.isRecord = true; // marking this as a record
199+
JVMClassInfo.this.recordComponents = new RecordComponentInfo[count]; // init array
200+
}
201+
202+
@Override
203+
public void setRecordComponent(ClassFile cf, Object tag, int index, String name, String descriptor, int attributesCount) {
204+
// Create a basic RecordComponentInfo object. this can be the default
205+
// TODO: attributes like signature/annotations will be added later
206+
RecordComponentInfo rci = new RecordComponentInfo(name, descriptor, null, null, null);
207+
JVMClassInfo.this.recordComponents[index] = rci;
208+
}
209+
210+
@Override
211+
public void setRecordComponentAttribute(ClassFile cf, Object tag, int componentIndex, int attrIndex, String attrName, int attrLength) {
212+
RecordComponentInfo rci = JVMClassInfo.this.recordComponents[componentIndex];
213+
214+
String name = rci.getName();
215+
String descriptor = rci.getDescriptor();
216+
String signature = rci.getSignature();
217+
AnnotationInfo[] annotations = rci.getAnnotations();
218+
TypeAnnotationInfo[] typeAnnotations = rci.getTypeAnnotations();
219+
220+
if (attrName.equals(ClassFile.SIGNATURE_ATTR)) {
221+
// Use the signature consumer pattern
222+
cf.parseSignatureAttr(this, rci);
223+
signature = rci.getSignature();
224+
}
225+
else if (attrName.equals(ClassFile.RUNTIME_VISIBLE_ANNOTATIONS_ATTR)) {
226+
annotations = new AnnotationInfo[0]; // Initialize or preserve existing
227+
cf.parseAnnotationsAttr(this, rci);
228+
annotations = rci.getAnnotations();
229+
}
230+
else if (attrName.equals(ClassFile.RUNTIME_INVISIBLE_ANNOTATIONS_ATTR)) {
231+
cf.parseAnnotationsAttr(this, rci);
232+
// we might need to merge with existing annotations
233+
}
234+
else if (attrName.equals(ClassFile.RUNTIME_VISIBLE_TYPE_ANNOTATIONS_ATTR)) {
235+
// Set up for type annotation parsing
236+
typeAnnotations = new TypeAnnotationInfo[0];
237+
cf.parseTypeAnnotationsAttr(this, rci);
238+
typeAnnotations = rci.getTypeAnnotations();
239+
}
240+
else if (attrName.equals(ClassFile.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS_ATTR)) {
241+
cf.parseTypeAnnotationsAttr(this, rci);
242+
}
243+
244+
// a new RecordComponentInfo with all updated attributes
245+
JVMClassInfo.this.recordComponents[componentIndex] =
246+
new RecordComponentInfo(name, descriptor, signature, annotations, typeAnnotations);
247+
}
248+
249+
@Override
250+
public void setRecordComponentsDone(ClassFile cf, Object tag) {
251+
// TODO: finalize logic here if needed or whatever we can leave it for now
252+
}
253+
192254
//--- inner/enclosing classes
193255
@Override
194256
public void setInnerClassCount (ClassFile cf, Object tag, int classCount) {

src/main/gov/nasa/jpf/vm/ClassInfo.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ public class ClassInfo extends InfoObject implements Iterable<MethodInfo>, Gener
144144
protected boolean isReferenceArray = false;
145145
protected boolean isAbstract = false;
146146
protected boolean isBuiltin = false;
147+
protected boolean isRecord = false;
147148

148149
// that's ultimately where we keep the attributes
149150
// <2do> this is currently quite redundant, but these are used in reflection
@@ -222,7 +223,10 @@ public class ClassInfo extends InfoObject implements Iterable<MethodInfo>, Gener
222223
/** from where the corresponding classfile was loaded (if this is not a builtin) */
223224
protected gov.nasa.jpf.vm.ClassFileContainer container;
224225

225-
226+
/** Array of Record components if this class is a record **/
227+
protected RecordComponentInfo[] recordComponents;
228+
229+
226230
/**
227231
* a search global numeric id that is only unique within this ClassLoader namespace. Ids are
228232
* computed by the ClassLoaderInfo/Statics implementation during ClassInfo registration
@@ -866,6 +870,13 @@ public ClassInfo getClassInfo() {
866870
return this;
867871
}
868872

873+
/**
874+
* Returns the array of record components if this class is a record, or null otherwise.
875+
*/
876+
public RecordComponentInfo[] getRecordComponents() {
877+
return recordComponents;
878+
}
879+
869880
protected void setAssertionStatus() {
870881
if(isInitialized()) {
871882
return;
@@ -928,6 +939,8 @@ public boolean isThreadClassInfo() {
928939
return isThreadClassInfo;
929940
}
930941

942+
public boolean isRecord() { return isRecord; }
943+
931944
protected void checkNoClinitInitialization(){
932945
if (!isInitialized()){
933946
ThreadInfo ti = ThreadInfo.getCurrentThread();
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package gov.nasa.jpf.vm;
2+
3+
/**
4+
* Class representing a Record component in a Java 17+ record class
5+
*/
6+
7+
public class RecordComponentInfo {
8+
private final String name;
9+
private final String descriptor;
10+
private final String signature;
11+
private final AnnotationInfo[] annotations;
12+
private final TypeAnnotationInfo[] typeAnnotations;
13+
14+
public RecordComponentInfo(String name, String descriptor, String signature,
15+
AnnotationInfo[] annotations, TypeAnnotationInfo[] typeAnnotations) {
16+
this.name = name;
17+
this.descriptor = descriptor;
18+
this.signature = signature;
19+
this.annotations = annotations;
20+
this.typeAnnotations = typeAnnotations;
21+
}
22+
23+
public String getName() {
24+
return name;
25+
}
26+
27+
public String getDescriptor() {
28+
return descriptor;
29+
}
30+
31+
public String getSignature() {
32+
return signature;
33+
}
34+
35+
public AnnotationInfo[] getAnnotations() {
36+
return annotations;
37+
}
38+
39+
public TypeAnnotationInfo[] getTypeAnnotations() {
40+
return typeAnnotations;
41+
}
42+
}

0 commit comments

Comments
 (0)