/
JavaType.java
289 lines (253 loc) · 6 KB
/
JavaType.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
// -*- Mode: Java; indent-tabs-mode: t; tab-width: 4 -*-
// ---------------------------------------------------------------------------
// Multi-Phasic Applications: SquirrelJME
// Copyright (C) Stephanie Gawroriski <xer@multiphasicapps.net>
// Copyright (C) Multi-Phasic Applications <multiphasicapps.net>
// ---------------------------------------------------------------------------
// SquirrelJME is under the GNU General Public License v3+, or later.
// See license.mkd for licensing and copyright information.
// ---------------------------------------------------------------------------
package net.multiphasicapps.classfile;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.util.Objects;
/**
* This represents a type which may be used on the stack or within local
* variables within the virtual machine.
*
* @since 2017/07/26
*/
public final class JavaType
{
/** The top of a long. */
public static final JavaType TOP_LONG =
new JavaType(1);
/** The top of a double. */
public static final JavaType TOP_DOUBLE =
new JavaType(2);
/** Top of an undefined type. */
public static final JavaType TOP_UNDEFINED =
new JavaType(3);
/** Nothing. */
public static final JavaType NOTHING =
new JavaType(4);
/** Integer. */
public static final JavaType INTEGER =
new JavaType(new FieldDescriptor("I"));
/** Long. */
public static final JavaType LONG =
new JavaType(new FieldDescriptor("J"));
/** Float. */
public static final JavaType FLOAT =
new JavaType(new FieldDescriptor("F"));
/** Double. */
public static final JavaType DOUBLE =
new JavaType(new FieldDescriptor("D"));
/** The type this refers to. */
protected final FieldDescriptor type;
/** Internal property. */
private final int _internal;
/** String representation of this table. */
private volatile Reference<String> _string;
/**
* Initializes the stack map type.
*
* @param __cn The name of the field.
* @param __init Is this object initialized?
* @throws NullPointerException On null arguments.
* @since 2017/07/28
*/
public JavaType(ClassName __cn)
throws NullPointerException
{
this(new FieldDescriptor((__cn.isArray() ? __cn.toString() :
"L" + __cn + ";")));
}
/**
* Initializes the stack map type.
*
* @param __f The field type.
* @throws NullPointerException On null arguments.
* @since 2017/07/28
*/
public JavaType(FieldDescriptor __f)
throws IllegalStateException, NullPointerException
{
// Check
if (__f == null)
throw new NullPointerException("NARG");
// Promote to integer since the VM does not have a representation for
// types smaller than int
PrimitiveType p = __f.primitiveType();
if (p != null && p.promotesToInt())
__f = new FieldDescriptor("I");
// Set
this._internal = 0;
this.type = __f;
}
/**
* Used internally to create special non-comparable types.
*
* @param __i Internal identifier.
* @throws RuntimeException If the internal value is zero.
* @since 2017/07/28
*/
private JavaType(int __i)
throws RuntimeException
{
// Check
if (__i == 0)
throw new RuntimeException("OOPS");
this._internal = __i;
this.type = null;
}
/**
* {@inheritDoc}
* @since 2017/07/28
*/
@Override
public boolean equals(Object __o)
{
// Check
if (!(__o instanceof JavaType))
return false;
JavaType o = (JavaType)__o;
return this._internal == o._internal &&
Objects.equals(this.type, o.type);
}
/**
* {@inheritDoc}
* @since 2017/07/28
*/
@Override
public int hashCode()
{
return this._internal ^ Objects.hashCode(this.type);
}
/**
* Is this an object type?
*
* @return {@code true} if this is an object type.
* @since 2017/08/13
*/
public boolean isObject()
{
FieldDescriptor type = this.type;
return (type != null && type.isObject());
}
/**
* Is this a primitive type?
*
* @return {@code true} if this is a primitive type.
* @since 2017/08/13
*/
public boolean isPrimitive()
{
FieldDescriptor type = this.type;
return (type != null && type.isPrimitive());
}
/**
* Is this the nothing type?
*
* @return If this is the nothing type.
* @since 2017/10/20
*/
public boolean isNothing()
{
return equals(NOTHING);
}
/**
* Is this a top type?
*
* @return If this is a top type or not.
* @since 2017/09/16
*/
public boolean isTop()
{
return equals(TOP_LONG) || equals(TOP_DOUBLE) || equals(TOP_UNDEFINED);
}
/**
* Is this a wide type?
*
* @return {@code true} if the type is a wide type.
* @since 2017/07/28
*/
public boolean isWide()
{
FieldDescriptor type = this.type;
if (type == null)
return false;
PrimitiveType pt = type.primitiveType();
return pt != null && pt.isWide();
}
/**
* Returns the type that is used for the top type.
*
* @return The associated top type used for this type or {@code null} if
* there is none.
* @since 2017/07/28
*/
public JavaType topType()
{
PrimitiveType pt = this.type.primitiveType();
if (pt == null)
return null;
switch (pt)
{
case LONG: return TOP_LONG;
case DOUBLE: return TOP_DOUBLE;
default:
return null;
}
}
/**
* {@inheritDoc}
* @since 2017/07/28
*/
@Override
public String toString()
{
// Unknown
Reference<String> ref = this._string;
String rv;
// Cache?
if (ref == null || null == (rv = ref.get()))
{
// Fixed type
if (this.equals(TOP_LONG))
rv = "top-long";
else if (this.equals(TOP_DOUBLE))
rv = "top-double";
else if (this.equals(TOP_UNDEFINED))
rv = "top-undefined";
else if (this.equals(NOTHING))
rv = "nothing";
// Other
else
rv = this.type.toString();
// Cache
this._string = new WeakReference<>(rv);
}
return rv;
}
/**
* Returns the type for this type.
*
* @return The type used.
* @since 2017/09/19
*/
public FieldDescriptor type()
{
return this.type;
}
/**
* Returns the width of the type.
*
* @return The width of the type.
* @since 2017/09/03
*/
public int width()
{
return (isWide() ? 2 : 1);
}
}