Skip to content

Commit 448c13d

Browse files
committed
Remove unnecessary calls to Class#getDeclaredX
1 parent 3926d85 commit 448c13d

1 file changed

Lines changed: 60 additions & 61 deletions

File tree

foundry-core/src/main/java/org/machinemc/foundry/util/ClassAccess.java

Lines changed: 60 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,16 @@
99
import org.objectweb.asm.signature.SignatureWriter;
1010

1111
import java.lang.invoke.MethodHandles;
12-
import java.lang.reflect.Constructor;
13-
import java.lang.reflect.Field;
14-
import java.lang.reflect.InvocationTargetException;
15-
import java.lang.reflect.Modifier;
12+
import java.lang.reflect.*;
1613
import java.util.Arrays;
1714
import java.util.Map;
1815
import java.util.concurrent.ConcurrentHashMap;
1916

2017
public final class ClassAccess {
21-
18+
2219
private static final Map<FieldAccessKey<?>, FieldAccess<?, ?>> fieldCache = new ConcurrentHashMap<>();
2320
private static final Map<MethodAccessKey<?>, MethodAccess<?, ?>> methodCache = new ConcurrentHashMap<>();
2421

25-
2622
private ClassAccess() {}
2723

2824
public static <T> T getField(Object source, String name) throws NoSuchFieldException {
@@ -105,35 +101,42 @@ public static <S> S invokeConstructor(Class<S> source, Class<?>[] parameters, Ob
105101
}
106102

107103
public static <S, T> FieldAccess<S, T> field(Class<S> source, String name) throws NoSuchFieldException {
108-
return fieldAccess(FieldAccessKey.of(source, name));
104+
return fieldAccess(new FieldAccessKey<>(source, name));
109105
}
110106

111-
private static <S, T> FieldAccess<S, T> fieldAccess(FieldAccessKey<S> key) {
112-
//noinspection unchecked
113-
return (FieldAccess<S, T>) fieldCache.computeIfAbsent(key, k -> {
114-
Class<?> aClass = defineHiddenIn(key.source(), generateFieldAccess(key));
107+
private static <S, T> FieldAccess<S, T> fieldAccess(FieldAccessKey<S> key) throws NoSuchFieldException {
108+
FieldAccess<?, ?> fieldAccess = fieldCache.get(key);
109+
if (fieldAccess == null) {
110+
Class<?> generated = defineHiddenIn(key.source(), generateFieldAccess(key));
115111
try {
116-
return (FieldAccess<?, ?>) aClass.getDeclaredConstructor().newInstance();
117-
} catch (InstantiationException | InvocationTargetException | NoSuchMethodException | IllegalAccessException e) {
112+
fieldAccess = (FieldAccess<?, ?>) generated.getDeclaredConstructor().newInstance();
113+
fieldCache.put(key, fieldAccess);
114+
} catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
118115
throw new RuntimeException(e); // Should not happen
119116
}
120-
});
117+
}
118+
//noinspection unchecked
119+
return (FieldAccess<S, T>) fieldAccess;
120+
121121
}
122122

123123
public static <S, T> MethodAccess<S, T> method(Class<S> source, String name, Class<?>... parameters) throws NoSuchMethodException {
124-
return methodAccess(MethodAccessKey.of(source, name, parameters));
124+
return methodAccess(new MethodAccessKey<>(source, name, parameters));
125125
}
126126

127-
private static <S, T> MethodAccess<S, T> methodAccess(MethodAccessKey<S> key) {
128-
//noinspection unchecked
129-
return (MethodAccess<S, T>) methodCache.computeIfAbsent(key, k -> {
130-
Class<?> aClass = defineHiddenIn(key.source(), generateMethodAccess(key));
127+
private static <S, T> MethodAccess<S, T> methodAccess(MethodAccessKey<S> key) throws NoSuchMethodException {
128+
MethodAccess<?, ?> methodAccess = methodCache.get(key);
129+
if (methodAccess == null) {
130+
Class<?> generated = defineHiddenIn(key.source(), generateMethodAccess(key));
131131
try {
132-
return (MethodAccess<?, ?>) aClass.getDeclaredConstructor().newInstance();
133-
} catch (InstantiationException | InvocationTargetException | NoSuchMethodException | IllegalAccessException e) {
132+
methodAccess = (MethodAccess<?, ?>) generated.getDeclaredConstructor().newInstance();
133+
methodCache.put(key, methodAccess);
134+
} catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
134135
throw new RuntimeException(e); // Should not happen
135136
}
136-
});
137+
}
138+
//noinspection unchecked
139+
return (MethodAccess<S, T>) methodAccess;
137140
}
138141

139142
private static Class<?> defineHiddenIn(Class<?> host, byte[] bytes) {
@@ -146,13 +149,16 @@ private static Class<?> defineHiddenIn(Class<?> host, byte[] bytes) {
146149
}
147150
}
148151

149-
private static byte[] generateFieldAccess(FieldAccessKey<?> key) {
152+
private static byte[] generateFieldAccess(FieldAccessKey<?> key) throws NoSuchFieldException {
150153
Type objectT = Type.getType(Object.class);
151154
Type fieldAccessT = Type.getType(FieldAccess.class);
152155
Type sourceT = Type.getType(key.source());
153-
Type fieldT = Type.getType(key.type());
154-
Class<?> boxedField = TypeUtils.box(key.type());
156+
157+
Field field = key.field();
158+
Type fieldT = Type.getType(field.getType());
159+
Class<?> boxedField = TypeUtils.box(field.getType());
155160
Type boxedFieldT = boxedField != null ? Type.getType(boxedField) : fieldT;
161+
boolean isStatic = Modifier.isStatic(field.getModifiers());
156162

157163
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
158164

@@ -172,12 +178,12 @@ private static byte[] generateFieldAccess(FieldAccessKey<?> key) {
172178
GeneratorAdapter ga = new GeneratorAdapter(mv, Opcodes.ACC_PUBLIC, "get", getterDesc);
173179

174180
ga.visitCode();
175-
if (!key.isStatic()) {
181+
if (isStatic) {
182+
ga.getStatic(sourceT, key.name(), fieldT);
183+
} else {
176184
ga.loadArg(0);
177185
ga.checkCast(sourceT);
178186
ga.getField(sourceT, key.name(), fieldT);
179-
} else {
180-
ga.getStatic(sourceT, key.name(), fieldT);
181187
}
182188
ga.box(fieldT);
183189
ga.returnValue();
@@ -188,19 +194,19 @@ private static byte[] generateFieldAccess(FieldAccessKey<?> key) {
188194
ga = new GeneratorAdapter(mv, Opcodes.ACC_PUBLIC, "set", setterDesc);
189195

190196
ga.visitCode();
191-
if (key.constant()) {
192-
ga.throwException(Type.getType(IllegalAccessException.class), "Cannot modify final field " + key.readable());
197+
if (Modifier.isFinal(field.getModifiers())) {
198+
ga.throwException(Type.getType(IllegalAccessException.class), "Cannot modify final field " + field);
193199
} else {
194-
if (!key.isStatic()) {
195-
ga.loadArg(0);
196-
ga.checkCast(sourceT);
200+
if (isStatic) {
197201
ga.loadArg(1);
198202
ga.unbox(fieldT);
199-
ga.putField(sourceT, key.name(), fieldT);
203+
ga.putStatic(sourceT, key.name(), fieldT);
200204
} else {
205+
ga.loadArg(0);
206+
ga.checkCast(sourceT);
201207
ga.loadArg(1);
202208
ga.unbox(fieldT);
203-
ga.putStatic(sourceT, key.name(), fieldT);
209+
ga.putField(sourceT, key.name(), fieldT);
204210
}
205211
ga.returnValue();
206212
}
@@ -210,12 +216,16 @@ private static byte[] generateFieldAccess(FieldAccessKey<?> key) {
210216
return cw.toByteArray();
211217
}
212218

213-
private static byte[] generateMethodAccess(MethodAccessKey<?> key) {
219+
private static byte[] generateMethodAccess(MethodAccessKey<?> key) throws NoSuchMethodException {
214220
Type objectT = Type.getType(Object.class);
215221
Type methodAccessT = Type.getType(MethodAccess.class);
216222
Type sourceT = Type.getType(key.source());
217-
Type returnTypeT = Type.getType(key.returnType());
218-
Class<?> boxedReturnType = TypeUtils.box(key.returnType());
223+
224+
Executable executable = key.executable();
225+
226+
Class<?> returnType = key.constructor() ? key.source() : ((java.lang.reflect.Method) executable).getReturnType();
227+
Type returnTypeT = key.constructor() ? sourceT : Type.getType(returnType);
228+
Class<?> boxedReturnType = TypeUtils.box(returnType);
219229
Type boxedReturnTypeT = boxedReturnType != null ? Type.getType(boxedReturnType) : returnTypeT;
220230
Type[] parametersT = Arrays.stream(key.parameters()).map(Type::getType).toArray(Type[]::new);
221231

@@ -242,7 +252,7 @@ private static byte[] generateMethodAccess(MethodAccessKey<?> key) {
242252
ga.dup();
243253
loadArgs(ga, key.parameters());
244254
ga.invokeConstructor(sourceT, new Method(key.name(), Type.VOID_TYPE, parametersT));
245-
} else if (key.isStatic()) {
255+
} else if (Modifier.isStatic(executable.getModifiers())) {
246256
loadArgs(ga, key.parameters());
247257
ga.invokeStatic(sourceT, new Method(key.name(), returnTypeT, parametersT));
248258

@@ -328,46 +338,35 @@ public interface MethodAccess<S, T> {
328338
T invoke(S source, Object... args);
329339
}
330340

331-
private record FieldAccessKey<S>(Class<? extends S> source, String name, Class<?> type, boolean constant, boolean isStatic) {
341+
private record FieldAccessKey<S>(Class<? extends S> source, String name) {
332342

333-
public String readable() {
334-
return (isStatic ? "static " : "") + type.getName() + " " + source.getName() + "." + name;
335-
}
336-
337-
public static <S> FieldAccessKey<S> of(Class<? extends S> source, String name) throws NoSuchFieldException {
338-
Field field = source.getDeclaredField(name);
339-
int modifiers = field.getModifiers();
340-
return new FieldAccessKey<>(source, name, field.getType(), (modifiers & Modifier.FINAL) != 0, (modifiers & Modifier.STATIC) != 0);
343+
public Field field() throws NoSuchFieldException {
344+
return source.getDeclaredField(name);
341345
}
342346

343347
}
344348

345-
private record MethodAccessKey<S>(Class<? extends S> source, String name, Class<?> returnType, Class<?>[] parameters, boolean isStatic) {
346-
347-
public static <S> MethodAccessKey<S> of(Class<? extends S> source, String name, Class<?>[] parameters) throws NoSuchMethodException {
348-
if ("<init>".equals(name)) {
349-
Constructor<?> constructor = source.getDeclaredConstructor(parameters);
350-
return new MethodAccessKey<>(source, name, source, constructor.getParameterTypes(), false);
351-
}
352-
java.lang.reflect.Method method = source.getDeclaredMethod(name, parameters);
353-
return new MethodAccessKey<>(source, name, method.getReturnType(), method.getParameterTypes(), (method.getModifiers() & Modifier.STATIC) != 0);
354-
}
349+
private record MethodAccessKey<S>(Class<? extends S> source, String name, Class<?>[] parameters) {
355350

356351
public boolean constructor() {
357352
return name.equals("<init>");
358353
}
359354

355+
public Executable executable() throws NoSuchMethodException {
356+
return constructor() ? source.getDeclaredConstructor(parameters) : source.getDeclaredMethod(name, parameters);
357+
}
358+
360359
@Override
361360
public boolean equals(Object o) {
362-
if (!(o instanceof MethodAccessKey<?>(Class<?> source1, String name1, Class<?> type, Class<?>[] parameters1, boolean aStatic)))
361+
if (!(o instanceof MethodAccessKey<?>(Class<?> source1, String name1, Class<?>[] parameters1)))
363362
return false;
364363

365-
return isStatic == aStatic && name.equals(name1) && returnType.equals(type) && Arrays.equals(parameters, parameters1) && source.equals(source1);
364+
return name.equals(name1) && Arrays.equals(parameters, parameters1) && source.equals(source1);
366365
}
367366

368367
@Override
369368
public int hashCode() {
370-
return Arrays.deepHashCode(new Object[]{source, name, returnType, parameters, isStatic});
369+
return Arrays.deepHashCode(new Object[]{source, name, parameters});
371370
}
372371

373372
}

0 commit comments

Comments
 (0)