1 /*
2 * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25 package jdk.internal.classfile.impl;
26
27 import java.lang.classfile.*;
28 import java.lang.classfile.attribute.*;
29 import java.lang.classfile.constantpool.ClassEntry;
30 import java.lang.classfile.constantpool.ConstantPool;
31 import java.lang.reflect.AccessFlag;
32 import java.util.List;
33 import java.util.Optional;
34 import java.util.function.Consumer;
35
36 import jdk.internal.access.SharedSecrets;
37
38 public final class ClassImpl
39 extends AbstractElement
40 implements ClassModel {
41 final ClassReaderImpl reader;
42 private final int attributesPos;
43 private final List<MethodModel> methods;
44 private final List<FieldModel> fields;
45 private List<Attribute<?>> attributes;
46 private List<ClassEntry> interfaces;
47
48 public ClassImpl(byte[] cfbytes, ClassFileImpl context) {
49 this.reader = new ClassReaderImpl(cfbytes, context);
50 int p = reader.interfacesPos;
51 int icnt = reader.readU2(p);
52 p += 2 + icnt * 2;
53 int fcnt = reader.readU2(p);
54 FieldImpl[] fields = new FieldImpl[fcnt];
55 p += 2;
56 for (int i = 0; i < fcnt; ++i) {
57 int startPos = p;
58 int attrStart = p + 6;
59 p = reader.skipAttributeHolder(attrStart);
60 fields[i] = new FieldImpl(reader, startPos, p, attrStart);
61 }
62 this.fields = List.of(fields);
63 int mcnt = reader.readU2(p);
64 MethodImpl[] methods = new MethodImpl[mcnt];
65 p += 2;
66 for (int i = 0; i < mcnt; ++i) {
67 int startPos = p;
68 int attrStart = p + 6;
69 p = reader.skipAttributeHolder(attrStart);
70 methods[i] = new MethodImpl(reader, startPos, p, attrStart);
71 }
72 this.methods = List.of(methods);
73 this.attributesPos = p;
74 reader.setContainedClass(this);
75 }
76
77 public int classfileLength() {
78 return reader.classfileLength();
79 }
80
81 @Override
82 public AccessFlags flags() {
83 return new AccessFlagsImpl(AccessFlag.Location.CLASS, reader.flags());
84 }
85
86 @Override
87 public int majorVersion() {
88 return reader.readU2(6);
89 }
90
91 @Override
92 public int minorVersion() {
93 return reader.readU2(4);
94 }
95
96 @Override
97 public ConstantPool constantPool() {
98 return reader;
99 }
100
101 @Override
102 public ClassEntry thisClass() {
103 return reader.thisClassEntry();
104 }
105
106 @Override
107 public Optional<ClassEntry> superclass() {
108 return reader.superclassEntry();
109 }
110
111 @Override
112 public List<ClassEntry> interfaces() {
113 if (interfaces == null) {
114 int pos = reader.thisClassPos() + 4;
115 int cnt = reader.readU2(pos);
116 pos += 2;
117 var arr = new Object[cnt];
118 for (int i = 0; i < cnt; ++i) {
119 arr[i] = reader.readEntry(pos, ClassEntry.class);
120 pos += 2;
121 }
122 this.interfaces = SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(arr);
123 }
124 return interfaces;
125 }
126
127 @Override
128 public List<Attribute<?>> attributes() {
129 if (attributes == null) {
130 attributes = BoundAttribute.readAttributes(this, reader, attributesPos, reader.customAttributes());
131 }
132 return attributes;
133 }
134
135 // ClassModel
136
137 @Override
138 public void forEach(Consumer<? super ClassElement> consumer) {
139 consumer.accept(flags());
140 consumer.accept(ClassFileVersion.of(majorVersion(), minorVersion()));
141 superclass().ifPresent(new Consumer<ClassEntry>() {
142 @Override
143 public void accept(ClassEntry entry) {
144 consumer.accept(Superclass.of(entry));
145 }
146 });
147 consumer.accept(Interfaces.of(interfaces()));
148 fields().forEach(consumer);
149 methods().forEach(consumer);
150 for (Attribute<?> attr : attributes()) {
151 if (attr instanceof ClassElement e)
152 consumer.accept(e);
153 }
154 }
155
156 @Override
157 public List<FieldModel> fields() {
158 return fields;
159 }
160
161 @Override
162 public List<MethodModel> methods() {
163 return methods;
164 }
165
166 @Override
167 public boolean isModuleInfo() {
168 AccessFlags flags = flags();
169 // move to where?
170 return flags.has(AccessFlag.MODULE)
171 && majorVersion() >= ClassFile.JAVA_9_VERSION
172 && thisClass().asInternalName().equals("module-info")
173 && (superclass().isEmpty())
174 && interfaces().isEmpty()
175 && fields().isEmpty()
176 && methods().isEmpty()
177 && verifyModuleAttributes();
178 }
179
180 @Override
181 public String toString() {
182 return String.format("ClassModel[thisClass=%s, flags=%d]", thisClass().name().stringValue(), flags().flagsMask());
183 }
184
185 private boolean verifyModuleAttributes() {
186 if (findAttribute(Attributes.module()).isEmpty())
187 return false;
188
189 return attributes().stream().allMatch(a ->
190 a instanceof ModuleAttribute
191 || a instanceof ModulePackagesAttribute
192 || a instanceof ModuleHashesAttribute
193 || a instanceof ModuleMainClassAttribute
194 || a instanceof ModuleResolutionAttribute
195 || a instanceof ModuleTargetAttribute
196 || a instanceof InnerClassesAttribute
197 || a instanceof SourceFileAttribute
198 || a instanceof SourceDebugExtensionAttribute
199 || a instanceof RuntimeVisibleAnnotationsAttribute
200 || a instanceof RuntimeInvisibleAnnotationsAttribute
201 || a instanceof CustomAttribute);
202 }
203 }