diff --git a/src/org/openjdk/asmtools/jasm/ClassArrayAttr.java b/src/org/openjdk/asmtools/jasm/ClassArrayAttr.java new file mode 100644 index 0000000..0aaf9e9 --- /dev/null +++ b/src/org/openjdk/asmtools/jasm/ClassArrayAttr.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2020, 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 org.openjdk.asmtools.jasm; + +import java.io.IOException; +import java.util.List; + +/** + * Base class of the "classes[]" data of attributes + *

+ * JEP 181 (Nest-based Access Control): class file 55.0 + * NestMembers_attribute { + * u2 attribute_name_index; + * u4 attribute_length; + * u2 number_of_classes; + * u2 classes[number_of_classes]; + * } + *

+ * JEP 360 (Sealed types): class file 59.65535 + * PermittedSubtypes_attribute { + * u2 attribute_name_index; + * u4 attribute_length; + * u2 permitted_subtypes_count; + * u2 classes[permitted_subtypes_count]; + * } + */ +public class ClassArrayAttr extends AttrData { + + List classes; + + public ClassArrayAttr(String attributeName, ClassData cdata, List classes) { + super(cdata, attributeName); + this.classes = classes; + } + + @Override + public int attrLength() { + return 2 + classes.size() * 2; + } + + @Override + public void write(CheckedDataOutputStream out) throws IOException { + super.write(out); + out.writeShort(classes.size()); + for (ConstantPool.ConstCell c : classes) { + out.writeShort(c.arg); + } + } +} diff --git a/src/org/openjdk/asmtools/jasm/ClassData.java b/src/org/openjdk/asmtools/jasm/ClassData.java index d11f70d..3712e09 100644 --- a/src/org/openjdk/asmtools/jasm/ClassData.java +++ b/src/org/openjdk/asmtools/jasm/ClassData.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2020, 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 @@ -55,6 +55,9 @@ class ClassData extends MemberData { // JEP 359 - Record attribute since class file 58.65535 private RecordData recordData; + // JEP 360 - PermittedSubtypes attribute since class file 59.65535 + private PermittedTypesAttr permittedTypesAttr; + ModuleAttr moduleAttribute = null; Environment env; protected ConstantPool pool; @@ -296,11 +299,17 @@ class ClassData extends MemberData { nestHostAttr = new CPXAttr(this, AttrTag.ATT_NestHost.parsekey(), hostClass); } - public void addNestMembers(List nestMemberClasses) { + public void addNestMembers(List classes) { env.traceln("addNestMembers"); - nestMembersAttr = new NestMembersAttr(this, nestMemberClasses); + nestMembersAttr = new NestMembersAttr(this, classes); } + public void addPermittedSubtypes(List classes) { + env.traceln("addPermittedSubtypes"); + permittedTypesAttr = new PermittedTypesAttr(this, classes); + } + + public void endClass() { sourceFileNameAttr = new CPXAttr(this, AttrTag.ATT_SourceFile.parsekey(), @@ -442,6 +451,9 @@ class ClassData extends MemberData { attrs.add(nestHostAttr); if(nestMembersAttributesExist()) attrs.add(nestMembersAttr); + // since class version 59.65535 (JEP 360) + if ( permittedSubtypesAttributesExist() ) + attrs.add(permittedTypesAttr); } return attrs; } @@ -496,6 +508,8 @@ class ClassData extends MemberData { public boolean nestMembersAttributesExist() { return nestMembersAttr != null; } + public boolean permittedSubtypesAttributesExist() { return permittedTypesAttr != null; } + public boolean recordAttributeExists() { return recordData != null; } /** diff --git a/src/org/openjdk/asmtools/jasm/JasmTokens.java b/src/org/openjdk/asmtools/jasm/JasmTokens.java index d53d49b..0612cc6 100644 --- a/src/org/openjdk/asmtools/jasm/JasmTokens.java +++ b/src/org/openjdk/asmtools/jasm/JasmTokens.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2020, 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 @@ -308,10 +308,12 @@ public class JasmTokens { // Declaration keywords BOOTSTRAPMETHOD (172, "BOOTSTRAPMETHOD", "BootstrapMethod", EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.MODULE_NAME ), KeywordType.KEYWORD), - NESTHOST (173, "NESTHOST", "NestHost", EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.MODULE_NAME ), KeywordType.KEYWORD), - NESTMEMBERS (174, "NESTMEMBERS", "NestMembers", EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.MODULE_NAME ), KeywordType.KEYWORD), + NESTHOST (173, "NESTHOST", "NestHost", EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.MODULE_NAME ), KeywordType.KEYWORD), + NESTMEMBERS (174, "NESTMEMBERS", "NestMembers", EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.MODULE_NAME ), KeywordType.KEYWORD), // - RECORD (175, "RECORD", "Record", EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.MODULE_NAME ), KeywordType.KEYWORD), + RECORD (175, "RECORD", "Record", EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.MODULE_NAME ), KeywordType.KEYWORD), + // + PERMITTEDSUBTYPES (176, "PERMITTEDSUBTYPES", "PermittedSubtypes", EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.MODULE_NAME ), KeywordType.KEYWORD), //Module statements REQUIRES (180, "REQUIRES", "requires", EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.MODULE_NAME ), KeywordType.KEYWORD), diff --git a/src/org/openjdk/asmtools/jasm/NestMembersAttr.java b/src/org/openjdk/asmtools/jasm/NestMembersAttr.java index 362801d..143c743 100644 --- a/src/org/openjdk/asmtools/jasm/NestMembersAttr.java +++ b/src/org/openjdk/asmtools/jasm/NestMembersAttr.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2020, 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 @@ -22,33 +22,20 @@ */ package org.openjdk.asmtools.jasm; -import java.io.IOException; import java.util.List; /** - * The NestMembers attribute data - *

- * since class file 55.0 (JEP 181) + * The "classes[]" data of attributes + * JEP 181 (Nest-based Access Control): class file 55.0 + * NestMembers_attribute { + * u2 attribute_name_index; + * u4 attribute_length; + * u2 number_of_classes; + * u2 classes[number_of_classes]; + * } */ -public class NestMembersAttr extends AttrData { - List nestMembers; - - public NestMembersAttr(ClassData cdata, List nestMembers){ - super(cdata, Tables.AttrTag.ATT_NestMembers.parsekey()); - this.nestMembers = nestMembers; - } - - @Override - public int attrLength() { - return 2 + nestMembers.size() * 2; - } - - @Override - public void write(CheckedDataOutputStream out) throws IOException { - super.write(out); - out.writeShort(nestMembers.size()); - for (ConstantPool.ConstCell c : nestMembers) { - out.writeShort(c.arg); - } +public class NestMembersAttr extends ClassArrayAttr { + public NestMembersAttr(ClassData cdata, List classes) { + super(Tables.AttrTag.ATT_NestMembers.parsekey(), cdata, classes); } } diff --git a/src/org/openjdk/asmtools/jasm/Parser.java b/src/org/openjdk/asmtools/jasm/Parser.java index eb6a4a0..ea6d3a8 100644 --- a/src/org/openjdk/asmtools/jasm/Parser.java +++ b/src/org/openjdk/asmtools/jasm/Parser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2020, 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 @@ -369,7 +369,7 @@ class Parser extends ParseBase { // either a CONSTANT_Methodref_info structure or a CONSTANT_InterfaceMethodref_info structure (ยง4.4.2) // representing a class's or interface's method for which a method handle is to be created. ConstType ctype = ConstType.CONSTANT_METHOD; - if ( this.cd.cfv.major_version() >= 52 && Modifiers.isInterface(this.cd.access) ) { + if (this.cd.cfv.major_version() >= 52 && Modifiers.isInterface(this.cd.access)) { ctype = ConstType.CONSTANT_INTERFACEMETHOD; } refCell = pool.FindCell(cpParser.parseConstValue(ctype)); @@ -561,28 +561,67 @@ class Parser extends ParseBase { while (true) { nextmod = 0; switch (scanner.token) { - case PUBLIC: nextmod = ACC_PUBLIC; break; - case PRIVATE: nextmod = ACC_PRIVATE; break; - case PROTECTED: nextmod = ACC_PROTECTED; break; - case STATIC: nextmod = ACC_STATIC; break; - case FINAL: nextmod = ACC_FINAL; break; - case SYNCHRONIZED: nextmod = ACC_SYNCHRONIZED; break; - case SUPER: nextmod = ACC_SUPER; break; - case VOLATILE: nextmod = ACC_VOLATILE; break; - case BRIDGE: nextmod = ACC_BRIDGE; break; - case TRANSIENT: nextmod = ACC_TRANSIENT; break; - case VARARGS: nextmod = ACC_VARARGS; break; - case NATIVE: nextmod = ACC_NATIVE; break; - case INTERFACE: nextmod = ACC_INTERFACE; break; - case ABSTRACT: nextmod = ACC_ABSTRACT; break; - case STRICT: nextmod = ACC_STRICT; break; - case ENUM: nextmod = ACC_ENUM; break; - case SYNTHETIC: nextmod = ACC_SYNTHETIC; break; + case PUBLIC: + nextmod = ACC_PUBLIC; + break; + case PRIVATE: + nextmod = ACC_PRIVATE; + break; + case PROTECTED: + nextmod = ACC_PROTECTED; + break; + case STATIC: + nextmod = ACC_STATIC; + break; + case FINAL: + nextmod = ACC_FINAL; + break; + case SYNCHRONIZED: + nextmod = ACC_SYNCHRONIZED; + break; + case SUPER: + nextmod = ACC_SUPER; + break; + case VOLATILE: + nextmod = ACC_VOLATILE; + break; + case BRIDGE: + nextmod = ACC_BRIDGE; + break; + case TRANSIENT: + nextmod = ACC_TRANSIENT; + break; + case VARARGS: + nextmod = ACC_VARARGS; + break; + case NATIVE: + nextmod = ACC_NATIVE; + break; + case INTERFACE: + nextmod = ACC_INTERFACE; + break; + case ABSTRACT: + nextmod = ACC_ABSTRACT; + break; + case STRICT: + nextmod = ACC_STRICT; + break; + case ENUM: + nextmod = ACC_ENUM; + break; + case SYNTHETIC: + nextmod = ACC_SYNTHETIC; + break; case ANNOTATION_ACCESS: - nextmod = ACC_ANNOTATION; break; + nextmod = ACC_ANNOTATION; + break; - case DEPRECATED: nextmod = DEPRECATED_ATTRIBUTE; break; - case MANDATED: nextmod = ACC_MANDATED; break; + case DEPRECATED: + nextmod = DEPRECATED_ATTRIBUTE; + break; + case MANDATED: + nextmod = ACC_MANDATED; + break; default: return nextmod; } @@ -865,20 +904,21 @@ class Parser extends ParseBase { } /** - * Parse a NestMembers entry + * Parse a list of classes belonging to the [NestMembers | PermittedSubtypes] entry */ - private void parseNestMembers() throws Scanner.SyntaxError, IOException { - ArrayList nestMembers = new ArrayList<>(); + private void parseClasses(Consumer> classesConsumer) + throws Scanner.SyntaxError, IOException { + ArrayList classes = new ArrayList<>(); // Parses in the form: - // NESTMEMBERS IDENT(, IDENT)*; - debugStr(" [Parser.parseNestMembers]: <<>>"); + // (NESTMEMBERS|PERMITTEDSUBTYPES)? IDENT(, IDENT)*; + debugStr(" [Parser.parseClasses]: <<>>"); while (true) { String className = prependPackage(parseIdent(), true); - nestMembers.add(pool.FindCellClassByName(className)); - debugScan(" [Parser.parseNestMembers]: NestMembers: class " + className); + classes.add(pool.FindCellClassByName(className)); + debugScan(" [Parser.parseClasses]: class " + className); if (scanner.token != Token.COMMA) { scanner.expect(Token.SEMICOLON); - cd.addNestMembers(nestMembers); + classesConsumer.accept(classes); return; } scanner.scan(); @@ -886,7 +926,7 @@ class Parser extends ParseBase { } /** - * Parse a Record entry + * Parse the Record entry */ private void parseRecord() throws Scanner.SyntaxError, IOException { // Parses in the form: @@ -898,7 +938,7 @@ class Parser extends ParseBase { // SIGNATURE = (CPINDEX | STRING) debugScan("[Parser.parseRecord]: Begin "); RecordData rd = cd.setRecord(scanner.pos); -Component: + Component: while (true) { ConstCell nameCell, descCell, signatureCell = null; nameCell = parseName(); @@ -913,10 +953,10 @@ Component: case SEMICOLON: return; // EOR case ANNOTATION: - rd.setAnnotations( annotParser.scanAnnotations()); + rd.setAnnotations(annotParser.scanAnnotations()); break; default: - if( signatureCell != null ) { + if (signatureCell != null) { env.error(scanner.pos, "warn.signature.repeated"); } signatureCell = parseName(); @@ -1627,10 +1667,18 @@ Component: throw new Scanner.SyntaxError(); } scanner.scan(); - parseNestMembers(); + parseClasses(list -> cd.addNestMembers(list)); break; - case RECORD: - if( cd.recordAttributeExists() ) { + case PERMITTEDSUBTYPES: // JEP 360 + if (cd.nestMembersAttributesExist()) { + env.error(scanner.pos, "extra.permittedsubtypes.attribute"); + throw new Scanner.SyntaxError(); + } + scanner.scan(); + parseClasses(list -> cd.addPermittedSubtypes(list)); + break; + case RECORD: // JEP 359 + if (cd.recordAttributeExists()) { env.error(scanner.pos, "extra.record.attribute"); throw new Scanner.SyntaxError(); } diff --git a/src/org/openjdk/asmtools/jasm/PermittedTypesAttr.java b/src/org/openjdk/asmtools/jasm/PermittedTypesAttr.java new file mode 100644 index 0000000..9517b51 --- /dev/null +++ b/src/org/openjdk/asmtools/jasm/PermittedTypesAttr.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2018, 2020, 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 org.openjdk.asmtools.jasm; + +import java.util.List; + +/** + * The "classes[]" data of attributes + * JEP 360 (Sealed types): class file 59.65535 + * PermittedSubtypes_attribute { + * u2 attribute_name_index; + * u4 attribute_length; + * u2 permitted_subtypes_count; + * u2 classes[permitted_subtypes_count]; + * } + */ +public class PermittedTypesAttr extends ClassArrayAttr { + public PermittedTypesAttr(ClassData cdata, List classes) { + super(Tables.AttrTag.ATT_PermittedSubtypes.parsekey(), cdata, classes); + } +} diff --git a/src/org/openjdk/asmtools/jasm/Tables.java b/src/org/openjdk/asmtools/jasm/Tables.java index bf164d1..2c21a5f 100644 --- a/src/org/openjdk/asmtools/jasm/Tables.java +++ b/src/org/openjdk/asmtools/jasm/Tables.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2020, 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 @@ -227,7 +227,15 @@ public class Tables { // u2 components_count; // component_info components[components_count]; // } - ATT_Record (34, "ATT_Record", "Record"); + ATT_Record (34, "ATT_Record", "Record"), + // JEP 360 (Sealed types): class file 59.65535 + // PermittedSubtypes_attribute { + // u2 attribute_name_index; + // u4 attribute_length; + // u2 permitted_subtypes_count; + // u2 classes[permitted_subtypes_count]; + // } + ATT_PermittedSubtypes (35, "ATT_PermittedSubtypes", "PermittedSubtypes"); private final Integer value; private final String printval; diff --git a/src/org/openjdk/asmtools/jasm/i18n.properties b/src/org/openjdk/asmtools/jasm/i18n.properties index b882d2a..0da7dc5 100644 --- a/src/org/openjdk/asmtools/jasm/i18n.properties +++ b/src/org/openjdk/asmtools/jasm/i18n.properties @@ -1,4 +1,4 @@ -# Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2014, 2020, 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 @@ -77,23 +77,20 @@ err.const.def.expected=Constant declaration expected. err.const.undecl=Constant #{0} not declared. err.const.redecl=Constant {0} redeclared. warn.const0.redecl=Re-declaration of Constant #0 cannot be written to the class file. -#err.const.bsmindex=Bad Bootstrap Methods index {0} specified. -#warn.const.misused=Constant {0} was assumed to have another tag. err.field.expected=Field, method, NestMembers, NestHost or Record declaration expected. err.token.expected={0} expected. err.identifier.expected=Identifier expected. err.extra.nesthost.attribute=There may be at most one NestHost attribute. err.extra.nestmembers.attribute=There may be at most one NestMembers attribute. +err.extra.permittedsubtypes.attribute=There may be at most one PermittedSubtypes attribute. err.extra.record.attribute=There may be at most one Record attribute. err.both.nesthost.nestmembers.found=The attributes table of a ClassFile structure must not contain both a NestMembers attribute and a NestHost attribute. err.name.expected=Name expected, got {0}. err.module.name.expected=Module name expected, got {0}. err.int.expected=Integer expected. -err.neg.forbidden=Negative integer is not allowed here. err.value.large=Value doesn't fit in {0}. err.value.expected=Value expected. err.wrong.mnemocode=Invalid mnemocode ({0}). -#err.class.expected='class' or 'interface' keyword expected. err.default.redecl=Default statement already declared in this table. err.long.switchtable=Switchtable too long: > {0}. err.io.exception=I/O error in {0}. @@ -117,9 +114,7 @@ err.cannot.write=Cannot write to {0}. err.msig.malformed=Malformed method signature at char {0}. [err={1}] err.no.classname=Class name not defined. warn.msig.more255=Number of parameters too large ({0}>255). -#warn.msig.large=Number of parameters ({0}) exceeds max_locals value ({1}). warn.illslot=Local variable at Illegal slot {0}. -#warn.invalid.modifier=This modifier is not allowed here warn.repeated.modifier=Repeated modifier. warn.invalid.modifier.init=invalid modifier for method \"{0}\". warn.invalid.modifier.fiva=at most one of final and volatile modifiers can be used for a field @@ -155,10 +150,7 @@ err.stackmap.repeated=stack_map redeclared. err.version.expected=class file version expected err.invalid.innerclass=Invalid declaration of Inner Class err.invalid.bootstrapmethod=Invalid declaration of BootstrapMethod Entry -#err.table.expected=Table expected -#err.package.module.expected=package or module expected err.frametype.repeated=Frametype repeated -#err.module.expected=module expected err.invalid.paramnum=Invalid Parameter Number: {0}. err.duplicate.paramnum=Duplicate Parameter Number: {0}. err.paramname.constnum.invaltype=ParameterName CPX at {0} is not a ConstantString. @@ -188,7 +180,6 @@ warn.dot.will.be.converted=Forward slash \"/\" expected instead of dot \".\". Th # # Compiler Errors # -# comperr.hashcode.err="CV hash:{0}" comperr.constcell.nullvalset="Cell without value in setCell" comperr.constcell.nullvalhash="Cell without value in cpoolHashByValue" comperr.constcell.invarg="Cell[{0}] has #{1}" diff --git a/src/org/openjdk/asmtools/jdec/ClassData.java b/src/org/openjdk/asmtools/jdec/ClassData.java index bd6e5e7..2b603c6 100644 --- a/src/org/openjdk/asmtools/jdec/ClassData.java +++ b/src/org/openjdk/asmtools/jdec/ClassData.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2020, 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 @@ -262,7 +262,7 @@ class ClassData { } } - private void printCP(PrintWriter out) throws IOException { + private void printCP(PrintWriter out) { int length = CPlen; startArrayCmt(length, "Constant Pool"); out_println("; // first element is empty"); @@ -273,7 +273,7 @@ class ClassData { byte btag = types[i]; ConstType tg = tag(btag); int pos = cpe_pos[i]; - String tagstr = ""; + String tagstr; String valstr; int v1; long lv; @@ -359,14 +359,6 @@ class ClassData { return " at " + toHex(countedin.getPos()); } - private String getStringPosCond() { - if (printDetails) { - return getStringPos(); - } else { - return ""; - } - } - private String getCommentPosCond() { if (printDetails) { return " // " + getStringPos(); @@ -384,16 +376,16 @@ class ClassData { out_println("// invalid length of " + attrname + " attr: " + len + " (should be " + (expectedIndices * 2) + ") > "); printBytes(out, in, len); } else { - String outputString = ""; + StringBuilder outputString = new StringBuilder(); for (int k = 1; k <= expectedIndices; k++) { - outputString += ("#" + in.readUnsignedShort() + "; "); + outputString.append("#").append(in.readUnsignedShort()).append("; "); if (k % 16 == 0) { - out_println(outputString.replaceAll("\\s+$","")); - outputString = ""; + out_println(outputString.toString().replaceAll("\\s+$","")); + outputString = new StringBuilder(); } } - if (!outputString.isEmpty()) { - out_println(outputString.replaceAll("\\s+$","")); + if (outputString.length() > 0) { + out_println(outputString.toString().replaceAll("\\s+$","")); } } } @@ -740,11 +732,8 @@ class ClassData { // Read the attributes decodeAttrs(in, out); break; - case ATT_ConstantValue: - decodeCPXAttr(in, len, AttrName, out); - break; + case ATT_Exceptions: - case ATT_NestMembers: int count = in.readUnsignedShort(); startArrayCmt(count, AttrName); try { @@ -758,7 +747,7 @@ class ClassData { break; case ATT_LineNumberTable: int ll_num = in.readUnsignedShort(); - startArrayCmt(ll_num, AttrName); + startArrayCmt(ll_num, "line_number_table"); try { for (int i = 0; i < ll_num; i++) { out_println(in.readUnsignedShort() + " " + @@ -788,7 +777,7 @@ class ClassData { break; case ATT_InnerClasses: int ic_num = in.readUnsignedShort(); - startArrayCmt(ic_num, AttrName); + startArrayCmt(ic_num, "classes"); try { for (int i = 0; i < ic_num; i++) { out_println("#" + in.readUnsignedShort() + " #" + @@ -800,9 +789,6 @@ class ClassData { out_end("}"); } break; - case ATT_Signature: - decodeCPXAttr(in, len, AttrName, out); - break; case ATT_StackMap: int e_num = in.readUnsignedShort(); startArrayCmt(e_num, ""); @@ -887,9 +873,6 @@ class ClassData { case ATT_EnclosingMethod: decodeCPXAttrM(in, len, AttrName, out, 2); break; - case ATT_SourceFile: - decodeCPXAttr(in, len, AttrName, out); - break; case ATT_AnnotationDefault: decodeElementValue(in, out); break; @@ -980,10 +963,6 @@ class ClassData { out_end("}"); } break; - // JEP 181: class file 55.0 - case ATT_NestHost: - decodeCPXAttr(in, len, AttrName, out); - break; // MethodParameters_attribute { // u2 attribute_name_index; // u4 attribute_length; @@ -1026,13 +1005,48 @@ class ClassData { out_end("}"); } break; + case ATT_ConstantValue: + case ATT_Signature: + case ATT_SourceFile: + decodeCPXAttr(in, len, AttrName, out); + break; + // JEP 181 (Nest-based Access Control): class file 55.0 + // NestHost_attribute { + // u2 attribute_name_index; + // u4 attribute_length; + // u2 host_class_index; + // } + case ATT_NestHost: + decodeTypes(in, out, 1); + break; + // JEP 181 (Nest-based Access Control): class file 55.0 + // NestMembers_attribute { + // u2 attribute_name_index; + // u4 attribute_length; + // u2 number_of_classes; + // u2 classes[number_of_classes]; + // } + case ATT_NestMembers: + // JEP 360 (Sealed types): class file 59.65535 + // PermittedSubtypes_attribute { + // u2 attribute_name_index; + // u4 attribute_length; + // u2 permitted_subtypes_count; + // u2 classes[permitted_subtypes_count]; + // } + case ATT_PermittedSubtypes: + int nsubtypes = in.readUnsignedShort(); + startArrayCmt(nsubtypes, "classes"); + try { + decodeTypes(in, out, nsubtypes); + } finally { + out_end("}"); + } + break; default: + printBytes(out, in, len); if (AttrName == null) { - printBytes(out, in, len); endingComment = "Attr(#" + name_cpx + ")"; - } else { - // some kind of error? - printBytes(out, in, len); } } @@ -1168,13 +1182,13 @@ class ClassData { } private void decodeMembers(DataInputStream in, PrintWriter out, String groupName, String elementName) throws IOException { - int nfields = in.readUnsignedShort(); - traceln(groupName + "=" + nfields); - startArrayCmt(nfields, groupName); + int count = in.readUnsignedShort(); + traceln(groupName + "=" + count); + startArrayCmt(count, groupName); try { - for (int i = 0; i < nfields; i++) { + for (int i = 0; i < count; i++) { decodeInfo(in,out,elementName,true); - if (i + 1 < nfields) { + if (i + 1 < count) { out_println(";"); } } @@ -1205,7 +1219,7 @@ class ClassData { entityType = "class"; } if (!entityName.isEmpty() && (JcodTokens.keyword_token_ident(entityName) != JcodTokens.Token.IDENT || JcodTokens.constValue(entityName) != -1)) { - // Jcod can't parse a entityName matching a keyword or a constant value, + // JCod can't parse a entityName matching a keyword or a constant value, // then use the filename instead: out_begin(String.format("file \"%s.class\" {", entityName)); } else { @@ -1235,16 +1249,12 @@ class ClassData { traceln(i18n.getString("jdec.trace.access_thisCpx_superCpx", access, this_cpx, super_cpx)); out.println(); - // Read the interface names + // Read the interfaces int numinterfaces = in.readUnsignedShort(); traceln(i18n.getString("jdec.trace.numinterfaces", numinterfaces)); startArrayCmt(numinterfaces, "Interfaces"); try { - for (int i = 0; i < numinterfaces; i++) { - int intrf_cpx = in.readUnsignedShort(); - traceln(i18n.getString("jdec.trace.intrf", i, intrf_cpx)); - out_println("#" + intrf_cpx + ";"); - } + decodeTypes(in, out, numinterfaces); } finally { out_end("} // Interfaces\n"); } @@ -1267,6 +1277,20 @@ class ClassData { } } // end decodeClass() + private void decodeTypes(DataInputStream in, PrintWriter out, int count) throws IOException { + for (int i = 0; i < count; i++) { + int type_cpx = in.readUnsignedShort(); + traceln(i18n.getString("jdec.trace.type", i, type_cpx)); + out_print("#" + type_cpx + ";"); + if (printDetails) { + String name = (String) cpool[(int)cpool[type_cpx]]; + out.println(" // " + name + getStringPos()); + } else { + out.println(); + } + } + } + /* ====================================================== */ boolean DebugFlag = false; diff --git a/src/org/openjdk/asmtools/jdec/i18n.properties b/src/org/openjdk/asmtools/jdec/i18n.properties index b1c1abd..a27299c 100644 --- a/src/org/openjdk/asmtools/jdec/i18n.properties +++ b/src/org/openjdk/asmtools/jdec/i18n.properties @@ -1,4 +1,4 @@ -# Copyright (c) 2014 Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2014, 2020, 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 @@ -37,5 +37,5 @@ jdec.trace.CP_len=CP len= {0} jdec.trace.CP_entry=CP entry # {0} tag= {1} jdec.trace.access_thisCpx_superCpx=access={0} this_cpx={1} super_cpx={2} jdec.trace.numinterfaces=numinterfaces={0} -jdec.trace.intrf=\ -\ intrf_cpx[{0}]={1} +jdec.trace.type=\ +\ type_cpx[{0}]={1} diff --git a/src/org/openjdk/asmtools/jdis/ClassArrayData.java b/src/org/openjdk/asmtools/jdis/ClassArrayData.java new file mode 100644 index 0000000..60e697c --- /dev/null +++ b/src/org/openjdk/asmtools/jdis/ClassArrayData.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2018, 2020, 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 org.openjdk.asmtools.jdis; + +import java.io.DataInputStream; +import java.io.IOException; + +/** + * Base class of the "classes[]" data of attributes + *

+ * JEP 181 (Nest-based Access Control): class file 55.0 + * NestMembers_attribute { + * u2 attribute_name_index; + * u4 attribute_length; + * u2 number_of_classes; + * u2 classes[number_of_classes]; + * } + *

+ * JEP 360 (Sealed types): class file 59.65535 + * PermittedSubtypes_attribute { + * u2 attribute_name_index; + * u4 attribute_length; + * u2 permitted_subtypes_count; + * u2 classes[permitted_subtypes_count]; + * } + *

+ */ +public class ClassArrayData { + String name; + ClassData cls; + int[] classes; + private Options options = Options.OptionObject(); + + protected ClassArrayData(ClassData cls, String attrName) { + this.cls = cls; + this.name = attrName; + } + + public ClassArrayData read(DataInputStream in, int attribute_length) throws IOException, ClassFormatError { + int number_of_classes = in.readUnsignedShort(); + if (attribute_length != 2 + number_of_classes * 2) { + throw new ClassFormatError(name + "_attribute: Invalid attribute length"); + } + classes = new int[number_of_classes]; + for (int i = 0; i < number_of_classes; i++) { + classes[i] = in.readUnsignedShort(); + } + return this; + } + + public void print() { + String indexes = ""; + String names = ""; + boolean pr_cpx = options.contains(Options.PR.CPX); + cls.out.print(name + " "); + for (int i = 0; i < classes.length; i++) { + if (pr_cpx) { + indexes += (indexes.isEmpty() ? "" : ", ") + "#" + classes[i]; + } + names += (names.isEmpty() ? "" : ", ") + cls.pool.StringValue(classes[i]); + } + if (pr_cpx) { + cls.out.print(indexes + "; // "); + } + cls.out.print(names); + if (pr_cpx) { + cls.out.println(); + } else { + cls.out.println(";"); + } + } + +} diff --git a/src/org/openjdk/asmtools/jdis/ClassData.java b/src/org/openjdk/asmtools/jdis/ClassData.java index 3597937..2bc20cd 100644 --- a/src/org/openjdk/asmtools/jdis/ClassData.java +++ b/src/org/openjdk/asmtools/jdis/ClassData.java @@ -92,6 +92,9 @@ public class ClassData extends MemberData { // The NestMembers of this class (since class file: 55.0) protected NestMembersData nestMembers; + // The PermittedSubtypes of this class (JEP 360 (Sealed types): class file 59.65535) + protected PermittedSubtypesData permittedSubtypes; + // other parsing fields protected PrintWriter out; protected String pkgPrefix = ""; @@ -215,6 +218,10 @@ public class ClassData extends MemberData { case ATT_Record: record = new RecordData(this).read(in); break; + case ATT_PermittedSubtypes: + // Read PermittedSubtypes Attribute (JEP 360 (Sealed types): class file 59.65535) + permittedSubtypes = new PermittedSubtypesData(this).read(in, attrlen); + break; default: handled = false; break; @@ -288,6 +295,7 @@ public class ClassData extends MemberData { public void print() throws IOException { int k, l; String className = ""; + String sourceName = ""; if( isModuleUnit() ) { // Print the Annotations printAnnotations(visibleAnnotations); @@ -407,20 +415,16 @@ printSugar: out.println("{"); if ((options.contains(Options.PR.SRC)) && (source_cpx != 0)) { - String source_name = pool.getName(source_cpx); - out.println("\t// Compiled from " + source_name); + sourceName = String.format(" compiled from %s" + + "" , pool.getName(source_cpx)); try { - source = new TextLines(source_name); + source = new TextLines(sourceName); } catch (IOException ignored) {} } - // keep this new line for classes to pass huge test suite. - if(!isModuleUnit()) - out.println(); // Print the constant pool if (options.contains(Options.PR.CP)) { pool.print(out); - out.println(); } // Don't print fields, methods, inner classes and bootstrap methods if it is module-info entity if ( !isModuleUnit() ) { @@ -446,6 +450,10 @@ printSugar: record.print(); } + // Print PermittedSubtypes Attribute (JEP 360 (Sealed types): class file 59.65535) + if( permittedSubtypes != null) { + permittedSubtypes.print(); + } // Print the NestHost (since class file: 55.0) if(nestHost != null) { nestHost.print(); @@ -470,7 +478,11 @@ printSugar: } out.println(); } - out.println("} // end Class " + className); + + + + + out.println("} // end Class " + className + sourceName); } else { // Print module attributes moduleData.print(); diff --git a/src/org/openjdk/asmtools/jdis/ConstantPool.java b/src/org/openjdk/asmtools/jdis/ConstantPool.java index 01d3e07..99e6957 100644 --- a/src/org/openjdk/asmtools/jdis/ConstantPool.java +++ b/src/org/openjdk/asmtools/jdis/ConstantPool.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2020, 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 @@ -1049,7 +1049,7 @@ public class ConstantPool { continue; } - out.print("const #" + cpx + " = "); + out.print("\tconst #" + cpx + " = "); if (cns == null) { // do something @@ -1060,7 +1060,6 @@ public class ConstantPool { cpx += cns.size(); } } - out.println(); } /** diff --git a/src/org/openjdk/asmtools/jdis/InnerClassData.java b/src/org/openjdk/asmtools/jdis/InnerClassData.java index 3917615..8c7f300 100644 --- a/src/org/openjdk/asmtools/jdis/InnerClassData.java +++ b/src/org/openjdk/asmtools/jdis/InnerClassData.java @@ -66,7 +66,7 @@ class InnerClassData { if (outer_class_info_index != 0) { cls.out.print(" of #" + outer_class_info_index); } - cls.out.print("; //"); + cls.out.print("; // "); } if (inner_name_index != 0) { cls.out.print(cls.pool.getName(inner_name_index) + "="); diff --git a/src/org/openjdk/asmtools/jdis/MethodData.java b/src/org/openjdk/asmtools/jdis/MethodData.java index d8110f9..15c4bd5 100644 --- a/src/org/openjdk/asmtools/jdis/MethodData.java +++ b/src/org/openjdk/asmtools/jdis/MethodData.java @@ -336,6 +336,8 @@ public class MethodData extends MemberData { if (code != null) { code.print(); + } else { + out.println(); } } diff --git a/src/org/openjdk/asmtools/jdis/NestMembersData.java b/src/org/openjdk/asmtools/jdis/NestMembersData.java index c6bfa84..b5eee6b 100644 --- a/src/org/openjdk/asmtools/jdis/NestMembersData.java +++ b/src/org/openjdk/asmtools/jdis/NestMembersData.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2020, 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 @@ -30,49 +30,20 @@ import java.io.IOException; /** * The NestMembers attribute data *

- * since class file 55.0 (JEP 181) + * JEP 181 (Nest-based Access Control): class file 55.0 + * NestMembers_attribute { + * u2 attribute_name_index; + * u4 attribute_length; + * u2 number_of_classes; + * u2 classes[number_of_classes]; + * } */ -public class NestMembersData { - ClassData cls; - int[] classes; - private Options options = Options.OptionObject(); - +public class NestMembersData extends ClassArrayData { public NestMembersData(ClassData cls) { - this.cls = cls; + super(cls, JasmTokens.Token.NESTMEMBERS.parsekey()); } public NestMembersData read(DataInputStream in, int attribute_length) throws IOException, ClassFormatError { - int number_of_classes = in.readUnsignedShort(); - if (attribute_length != 2 + number_of_classes * 2 ) { - throw new ClassFormatError("ATT_NestMembers: Invalid attribute length"); - } - classes = new int[number_of_classes]; - for (int i = 0; i < number_of_classes; i++) { - classes[i] = in.readUnsignedShort(); - } - return this; + return (NestMembersData) super.read(in, attribute_length); } - - public void print() { - String indexes = ""; - String names = ""; - boolean pr_cpx = options.contains(Options.PR.CPX); - cls.out.print(JasmTokens.Token.NESTMEMBERS.parsekey() + " "); - for(int i = 0; i< classes.length; i++) { - if (pr_cpx) { - indexes += (indexes.isEmpty() ? "" : ", ") + "#" + classes[i]; - } - names += (names.isEmpty() ? "" : ", ") + cls.pool.StringValue(classes[i]); - } - if (pr_cpx) { - cls.out.print(indexes + "; //"); - } - cls.out.print(names); - if (pr_cpx) { - cls.out.println(); - } else { - cls.out.println(";"); - } - } - } diff --git a/src/org/openjdk/asmtools/jdis/PermittedSubtypesData.java b/src/org/openjdk/asmtools/jdis/PermittedSubtypesData.java new file mode 100644 index 0000000..7b5901c --- /dev/null +++ b/src/org/openjdk/asmtools/jdis/PermittedSubtypesData.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2020, 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 org.openjdk.asmtools.jdis; + +import org.openjdk.asmtools.jasm.JasmTokens; + +import java.io.DataInputStream; +import java.io.IOException; + +/** + * The NestMembers attribute data + *

+ * JEP 360 (Sealed types): class file 59.65535 + * PermittedSubtypes_attribute { + * u2 attribute_name_index; + * u4 attribute_length; + * u2 permitted_subtypes_count; + * u2 classes[permitted_subtypes_count]; + * } + */ +public class PermittedSubtypesData extends ClassArrayData { + public PermittedSubtypesData(ClassData cls) { + super(cls, JasmTokens.Token.PERMITTEDSUBTYPES.parsekey()); + } + + public PermittedSubtypesData read(DataInputStream in, int attribute_length) throws IOException, ClassFormatError { + return (PermittedSubtypesData) super.read(in, attribute_length); + } +}