1 // -*- Mode: Java; indent-tabs-mode: t; tab-width: 4 -*-
2 // ---------------------------------------------------------------------------
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
;
21 * This represents a method which is used to execute byte code.
25 public final class Method
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
;
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}.
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");
99 this.classflags
= __cf
;
100 this.classname
= __tn
;
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
;
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.
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
;
136 // Otherwise, load a representation of it
137 Reference
<ByteCode
> ref
= this._bytecode
;
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
)));
153 public final MethodFlags
flags()
155 return this.methodflags
;
159 * Returns the index of the method.
161 * @return The method index.
164 public final MethodHandle
handle()
166 Reference
<MethodHandle
> ref
= this._index
;
169 if (ref
== null || null == (rv
= ref
.get()))
170 this._index
= new SoftReference
<>(rv
= new MethodHandle(
171 this.classname
, this.methodname
, this.methodtype
));
177 * Returns if this method is effectively final, meaning that it cannot be
180 * @return If this method is effectively final or not.
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.
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.
205 public final boolean isStaticInitializer()
207 return this.methodname
.isStaticInitializer();
213 * @return The method index.
216 public final int methodIndex()
218 return this.methodIndex
;
222 * Returns the name of the method.
224 * @return The method name.
227 public final MethodName
name()
229 return this.methodname
;
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
));
250 * Returns the constant pool this method uses.
252 * @return The constant pool which is used.
255 public final Pool
pool()
261 * Returns the method's type.
263 * @return The type of the method.
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
280 * @throws IOException On read errors.
281 * @throws NullPointerException On null arguments.
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 ||
290 throw new NullPointerException("NARG");
292 int nm
= __in
.readUnsignedShort();
293 Method
[] rv
= new Method
[nm
];
294 Set
<NameAndType
> dup
= new HashSet
<>();
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
));
323 AttributeTable attrs
= AttributeTable
.parse(__pool
, __in
);
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.
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
));
341 rv
[i
] = new Method(__ver
, __cf
, __tn
, __pool
, flags
, name
, type
,
342 code
, annotations
, i
);