Remove exported everywhere.
[SquirrelJME.git] / modules / tool-classfile / src / main / java / net / multiphasicapps / classfile / Method.java
blobeed73f35ea928589c9ca25b287289d1f695a8e62
1 // -*- Mode: Java; indent-tabs-mode: t; tab-width: 4 -*-
2 // ---------------------------------------------------------------------------
3 // SquirrelJME
4 // Copyright (C) Stephanie Gawroriski <xer@multiphasicapps.net>
5 // ---------------------------------------------------------------------------
6 // SquirrelJME is under the GNU General Public License v3+, or later.
7 // See license.mkd for licensing and copyright information.
8 // ---------------------------------------------------------------------------
10 package net.multiphasicapps.classfile;
12 import java.io.DataInputStream;
13 import java.io.IOException;
14 import java.lang.ref.Reference;
15 import java.lang.ref.SoftReference;
16 import java.lang.ref.WeakReference;
17 import java.util.HashSet;
18 import java.util.Set;
20 /**
21 * This represents a method which is used to execute byte code.
23 * @since 2017/09/30
25 public final class Method
26 extends Member
27 implements Annotated
29 /** The version of the class. */
30 protected final ClassVersion version;
32 /** The flags for class. */
33 protected final ClassFlags classflags;
35 /** The name of the current class. */
36 protected final ClassName classname;
38 /** The constant pool. */
39 protected final Pool pool;
41 /** The flags for the current method. */
42 protected final MethodFlags methodflags;
44 /** The name of the method. */
45 protected final MethodName methodname;
47 /** The type of the method. */
48 protected final MethodDescriptor methodtype;
50 /** Does this method have code? */
51 protected final boolean hascode;
53 /** The method index. */
54 protected final int methodIndex;
56 /** Annotated values. */
57 protected final AnnotationTable annotations;
59 /** The code attribute data, which is optional. */
60 private final byte[] _rawcodeattr;
62 /** The method byte code. */
63 private Reference<ByteCode> _bytecode;
65 /** Name and type reference. */
66 private Reference<MethodNameAndType> _nameandtype;
68 /** The method index. */
69 private Reference<MethodHandle> _index;
71 /**
72 * Initializes the method.
74 * @param __ver The class version.
75 * @param __cf The class flags.
76 * @param __tn The name of the class.
77 * @param __pool The constant pool.
78 * @param __mf The method flags.
79 * @param __mn The name of the method.
80 * @param __mt The method type.
81 * @param __mc An optional byte array representing the code attribute, the
82 * value is used directly.
83 * @param __avs Annotations associated with this method.
84 * @param __index The method index.
85 * @throws NullPointerException On null arguments except for {@code __mc}.
86 * @since 2017/09/30
88 Method(ClassVersion __ver, ClassFlags __cf, ClassName __tn, Pool __pool,
89 MethodFlags __mf, MethodName __mn, MethodDescriptor __mt, byte[] __mc,
90 AnnotationTable __avs, int __index)
91 throws NullPointerException
93 if (__ver == null || __cf == null || __tn == null || __pool == null ||
94 __mf == null || __mn == null || __mt == null || __avs == null)
95 throw new NullPointerException("NARG");
97 // Set
98 this.version = __ver;
99 this.classflags = __cf;
100 this.classname = __tn;
101 this.pool = __pool;
102 this.methodflags = __mf;
103 this.methodname = __mn;
104 this.methodtype = __mt;
105 this.annotations = __avs;
106 this._rawcodeattr = __mc;
107 this.hascode = !__mf.isNative() && !__mf.isAbstract();
108 this.methodIndex = __index;
112 * {@inheritDoc}
113 * @since 2018/03/06
115 @Override
116 public final AnnotationTable annotationTable()
118 return this.annotations;
122 * Returns the byte code for this method.
124 * @return The byte code for this method or {@code null} if there is none.
125 * @throws InvalidClassFormatException If the byte code is not valid.
126 * @since 2017/10/09
128 public final ByteCode byteCode()
129 throws InvalidClassFormatException
131 // If there is no code attribute there is no byte code
132 byte[] rawcodeattr = this._rawcodeattr;
133 if (!this.hascode)
134 return null;
136 // Otherwise, load a representation of it
137 Reference<ByteCode> ref = this._bytecode;
138 ByteCode rv;
140 if (ref == null || null == (rv = ref.get()))
141 this._bytecode = new SoftReference<>((rv = new ByteCode(
142 new WeakReference<>(this), this._rawcodeattr,
143 this.classname, this.methodflags)));
145 return rv;
149 * {@inheritDoc}
150 * @since 2017/10/11
152 @Override
153 public final MethodFlags flags()
155 return this.methodflags;
159 * Returns the index of the method.
161 * @return The method index.
162 * @since 2017/10/14
164 public final MethodHandle handle()
166 Reference<MethodHandle> ref = this._index;
167 MethodHandle rv;
169 if (ref == null || null == (rv = ref.get()))
170 this._index = new SoftReference<>(rv = new MethodHandle(
171 this.classname, this.methodname, this.methodtype));
173 return rv;
177 * Returns if this method is effectively final, meaning that it cannot be
178 * replaced.
180 * @return If this method is effectively final or not.
181 * @since 2017/10/16
183 public boolean isEffectivelyFinal()
185 return this.methodflags.isFinal() || this.classflags.isFinal();
189 * Returns whether this is a constructor or not.
191 * @return Whether this is a constructor or not.
192 * @since 2018/09/03
194 public final boolean isInstanceInitializer()
196 return this.methodname.isInstanceInitializer();
200 * Returns whether this is a static initializer or not.
202 * @return Whether this is a static initializer or not.
203 * @since 2018/09/03
205 public final boolean isStaticInitializer()
207 return this.methodname.isStaticInitializer();
211 * The method index.
213 * @return The method index.
214 * @since 2021/07/06
216 public final int methodIndex()
218 return this.methodIndex;
222 * Returns the name of the method.
224 * @return The method name.
225 * @since 2017/10/12
227 public final MethodName name()
229 return this.methodname;
233 * {@inheritDoc}
234 * @since 2017/10/10
236 @Override
237 public final MethodNameAndType nameAndType()
239 Reference<MethodNameAndType> ref = this._nameandtype;
240 MethodNameAndType rv;
242 if (ref == null || null == (rv = ref.get()))
243 this._nameandtype = new SoftReference<>(
244 rv = new MethodNameAndType(this.methodname, this.methodtype));
246 return rv;
250 * Returns the constant pool this method uses.
252 * @return The constant pool which is used.
253 * @since 2017/10/09
255 public final Pool pool()
257 return this.pool;
261 * Returns the method's type.
263 * @return The type of the method.
264 * @since 2017/10/16
266 public final MethodDescriptor type()
268 return this.methodtype;
272 * Decodes all methods from the input class data.
274 * @param __ver The version of the class.
275 * @param __tn The name of the owning class.
276 * @param __cf The flags for the owning class.
277 * @param __pool The constant pool for the class.
278 * @throws InvalidClassFormatException If the class is not formatted
279 * correctly.
280 * @throws IOException On read errors.
281 * @throws NullPointerException On null arguments.
282 * @since 2017/09/30
284 public static Method[] decode(ClassVersion __ver, ClassName __tn,
285 ClassFlags __cf, Pool __pool, DataInputStream __in)
286 throws InvalidClassFormatException, IOException, NullPointerException
288 if (__ver == null || __tn == null || __cf == null || __pool == null ||
289 __in == null)
290 throw new NullPointerException("NARG");
292 int nm = __in.readUnsignedShort();
293 Method[] rv = new Method[nm];
294 Set<NameAndType> dup = new HashSet<>();
296 // Parse methods
297 for (int i = 0; i < nm; i++)
299 // Read the flags but do not initialize them yet
300 int rawflags = __in.readUnsignedShort();
302 // Parse name, this is needed to see if it is a constructor
303 MethodName name = new MethodName(
304 __pool.<UTFConstantEntry>require(UTFConstantEntry.class,
305 __in.readUnsignedShort()).toString());
307 // Initialize the flags now that we know the class name, this way
308 // we can determine if this is a constructor or not
309 MethodFlags flags = new MethodFlags(__cf, name, rawflags);
311 // Continue reading the type
312 MethodDescriptor type = new MethodDescriptor(
313 __pool.<UTFConstantEntry>require(UTFConstantEntry.class,
314 __in.readUnsignedShort()).toString());
316 // {@squirreljme.error JC3f A duplicate method exists within the
317 // class. (The method name; The method descriptor)}
318 if (!dup.add(new NameAndType(name.toString(), type.toString())))
319 throw new InvalidClassFormatException(String.format(
320 "JC3f %s %s", name, type));
322 // Handle attributes
323 AttributeTable attrs = AttributeTable.parse(__pool, __in);
325 // Parse annotations
326 AnnotationTable annotations = AnnotationTable.parse(__pool, attrs);
328 // Get copy of the code attribute
329 Attribute maybecode = attrs.get("Code");
330 byte[] code = (maybecode == null ? null : maybecode.bytes());
332 // {@squirreljme.error JC3g The specified method does not have
333 // the correct matching for abstract and if code exists or not.
334 // (The current
335 // class; The method name; The method type; The method flags)}
336 if ((code == null) != (flags.isAbstract() | flags.isNative()))
337 throw new InvalidClassFormatException(String.format(
338 "JC3g %s %s %s %s", __tn, name, type, flags));
340 // Create
341 rv[i] = new Method(__ver, __cf, __tn, __pool, flags, name, type,
342 code, annotations, i);
345 // All done!
346 return rv;