This commit is contained in:
apucher
2023-01-08 14:45:03 +01:00
committed by wea_ondara
parent b805eed622
commit 74a8f56ab5
7 changed files with 682 additions and 213 deletions

View File

@@ -54,7 +54,7 @@ class ClassAnalyzerVisitor extends ClassVisitor {
var type = Type.getMethodType(descriptor);
var returnClassName = type.getReturnType().getClassName();
var parameterClassNames = Arrays.stream(type.getArgumentTypes()).map(Type::getClassName).toArray(String[]::new);
return new MethodAnalyzerVisitor(Opcodes.ASM9, className, name, returnClassName, parameterClassNames, entityAccess -> {
return new MethodAnalyzerVisitor(Opcodes.ASM9, className, name, access, returnClassName, parameterClassNames, entityAccess -> {
declaredConstructor.addAll(entityAccess.getDeclaredConstructors());
declaredGetters.addAll(entityAccess.getDeclaredGetters());
declaredSetters.addAll(entityAccess.getDeclaredSetters());

View File

@@ -6,6 +6,7 @@ import jef.asm.access.model.ConstructorParameterDescription;
import jef.asm.access.model.GetterDescription;
import jef.asm.access.model.SetterDescription;
import jef.asm.access.model.SuperConstructorParameterDescription;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.objectweb.asm.Handle;
import org.objectweb.asm.Label;
@@ -14,6 +15,7 @@ import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.Stack;
@@ -22,14 +24,15 @@ import java.util.function.Consumer;
@Getter
public class MethodAnalyzerVisitor extends MethodVisitor {//TODO verify param count
private final Consumer<ClassDescription> callback;
private final String methodClassName;
private final String declaringClassName;
private final String methodName;
private final int access;
private final String returnClassName;
private final String[] parameterClassNames;
private final String[] parameterClassNames;
private List<ConstructorParameterDescription> constructorParameterDescriptions = new ArrayList<>();
private List<SuperConstructorParameterDescription> superConstructorParameterDescriptions = new ArrayList<>();
private Stack<Integer> varIndexStack = new Stack<>();
private Stack<Var> varStack = new Stack<>();
private String fieldDeclaringClassName = null;
private String fieldName = null;
@@ -69,12 +72,19 @@ public class MethodAnalyzerVisitor extends MethodVisitor {//TODO verify param co
INVALID
}
protected MethodAnalyzerVisitor(int api, String methodClassName, String methodName, String returnClassName, String[] parameterClassNames, Consumer<ClassDescription> callback) {
protected MethodAnalyzerVisitor(int api, String declaringClassName, String methodName, int access, String returnClassName, String[] parameterClassNames, Consumer<ClassDescription> callback) {
super(api);
this.methodClassName = methodClassName;
this.declaringClassName = declaringClassName;
this.methodName = methodName;
this.access = access;
this.returnClassName = returnClassName;
this.parameterClassNames = parameterClassNames;
if (hasThis()) {
this.parameterClassNames = new String[parameterClassNames.length + 1];
System.arraycopy(parameterClassNames, 0, this.parameterClassNames, 1, parameterClassNames.length);
this.parameterClassNames[0] = declaringClassName;
} else {
this.parameterClassNames = parameterClassNames;
}
this.callback = callback;
}
@@ -122,7 +132,11 @@ public class MethodAnalyzerVisitor extends MethodVisitor {//TODO verify param co
@Override
public void visitVarInsn(int opcode, int varIndex) {
if (Set.of(Opcodes.ILOAD, Opcodes.LLOAD, Opcodes.FLOAD, Opcodes.DLOAD, Opcodes.ALOAD).contains(opcode)) {
varIndexStack.push(varIndex);
System.out.println(methodName + ": load_" + varIndex + ": " + (varIndex < parameterClassNames.length ? parameterClassNames[varIndex] : null));
if (varIndex == 5) {
int x = 0;
}
varStack.push(new Var(varIndex < parameterClassNames.length ? parameterClassNames[varIndex] : null, varIndex));
}
if (opcode == Opcodes.ALOAD && varIndex == 0) {
if (constructorStep == ConstructorSteps.CODE) {
@@ -160,6 +174,10 @@ public class MethodAnalyzerVisitor extends MethodVisitor {//TODO verify param co
super.visitVarInsn(opcode, varIndex);
}
private boolean hasThis() {
return (access & Opcodes.ACC_STATIC) == 0;
}
@Override
public void visitTypeInsn(int opcode, String type) {
constructorStep = ConstructorSteps.INVALID;
@@ -170,15 +188,15 @@ public class MethodAnalyzerVisitor extends MethodVisitor {//TODO verify param co
@Override
public void visitFieldInsn(int opcode, String owner, String name, String descriptor) {
var lastLoadedVarIndex = -1;
Var lastLoadedVar = null;
if (opcode == Opcodes.PUTFIELD) {
lastLoadedVarIndex = varIndexStack.pop();
varIndexStack.pop();
lastLoadedVar = varStack.pop();
varStack.pop();
constructorStep = constructorStep == ConstructorSteps.VAR_LOAD ? ConstructorSteps.PUT_FIELD : ConstructorSteps.INVALID;
getterStep = GetterSteps.INVALID;
setterStep = setterStep == SetterSteps.VAR_LOAD ? SetterSteps.PUT_FIELD : SetterSteps.INVALID;
} else if (opcode == Opcodes.GETFIELD) {
lastLoadedVarIndex = varIndexStack.pop();
lastLoadedVar = varStack.pop();
constructorStep = ConstructorSteps.INVALID;
getterStep = getterStep == GetterSteps.ALOAD_0 ? GetterSteps.GET_FIELD : GetterSteps.INVALID;
setterStep = SetterSteps.INVALID;
@@ -189,21 +207,21 @@ public class MethodAnalyzerVisitor extends MethodVisitor {//TODO verify param co
}
this.fieldDeclaringClassName = owner.replace("/", ".");
this.fieldName = name;
this.constructorParameterDescriptions.add(new ConstructorParameterDescription(lastLoadedVarIndex - 1, this.fieldDeclaringClassName, this.fieldName)); //lastLoadedVarIndex - 1 because arg 0 of an instance function is always this
this.constructorParameterDescriptions.add(new ConstructorParameterDescription(lastLoadedVar.getIndex() - 1, lastLoadedVar.getClassName(), this.fieldDeclaringClassName, this.fieldName)); //lastLoadedVar - 1 because arg 0 of an instance function is always this
super.visitFieldInsn(opcode, owner, name, descriptor);
}
@Override
public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) {
var argIndexes = new ArrayList<Integer>();
var args = new ArrayList<Var>();
for (var i = 0; i < Type.getArgumentTypes(descriptor).length; i++) {
argIndexes.add(0, varIndexStack.pop());
args.add(0, varStack.pop());
}
varIndexStack.pop(); // also pop ALOAD0
varStack.pop(); // also pop ALOAD0
if (opcode == Opcodes.INVOKESPECIAL && name.equals("<init>") //TODO does it have to be called '<init>' or is this just convention
&& Set.of(ConstructorSteps.PRE_SUPER_INIT_ALOAD_0, ConstructorSteps.PRE_SUPER_INIT_VAR_LOAD).contains(constructorStep)) {
for (int i = 0; i < argIndexes.size(); i++) {
superConstructorParameterDescriptions.add(new SuperConstructorParameterDescription(argIndexes.get(i), i));
&& Set.of(ConstructorSteps.PRE_SUPER_INIT_ALOAD_0, ConstructorSteps.PRE_SUPER_INIT_VAR_LOAD).contains(constructorStep)) {
for (int i = 0; i < args.size(); i++) {
superConstructorParameterDescriptions.add(new SuperConstructorParameterDescription(args.get(i).getIndex(), i));
}
constructorStep = ConstructorSteps.SUPER_INIT;
} else {
@@ -232,9 +250,6 @@ public class MethodAnalyzerVisitor extends MethodVisitor {//TODO verify param co
@Override
public void visitLabel(Label label) {
// constructorStep = ConstructorSteps.INVALID;
// getterStep = GetterSteps.INVALID;
// setterStep = SetterSteps.INVALID;
super.visitLabel(label);
}
@@ -300,9 +315,16 @@ public class MethodAnalyzerVisitor extends MethodVisitor {//TODO verify param co
public void visitEnd() {
super.visitEnd();
List<ConstructorDescription> constructors = constructorStep == ConstructorSteps.RETURN ? List.of(new ConstructorDescription(constructorParameterDescriptions, superConstructorParameterDescriptions)) : List.of();
List<GetterDescription> getters = getterStep == GetterSteps.RETURN ? List.of(new GetterDescription(methodClassName, methodName, returnClassName, parameterClassNames, fieldDeclaringClassName, fieldName)) : List.of();
List<SetterDescription> setters = setterStep == SetterSteps.RETURN ? List.of(new SetterDescription(methodClassName, methodName, returnClassName, parameterClassNames, fieldDeclaringClassName, fieldName)) : List.of();
List<GetterDescription> getters = getterStep == GetterSteps.RETURN ? List.of(new GetterDescription(declaringClassName, methodName, returnClassName, Arrays.stream(parameterClassNames).skip(hasThis() ? 1 : 0).toArray(String[]::new), fieldDeclaringClassName, fieldName)) : List.of();
List<SetterDescription> setters = setterStep == SetterSteps.RETURN ? List.of(new SetterDescription(declaringClassName, methodName, returnClassName, Arrays.stream(parameterClassNames).skip(hasThis() ? 1 : 0).toArray(String[]::new), fieldDeclaringClassName, fieldName)) : List.of();
var access = new ClassDescription(null, null, null, constructors, getters, setters);
callback.accept(access);
}
@AllArgsConstructor
@Getter
private static class Var {
private final String className;
private final int index;
}
}

View File

@@ -9,6 +9,7 @@ import lombok.ToString;
@ToString
public class ConstructorParameterDescription {
private final int parameterIndex;
private final String parameterClassName;
private final String declaringClassName;
private final String fieldName;
}

View File

@@ -15,7 +15,7 @@ public @interface Generated {
enum Type {
NONE,//no value is generated
IDENTITY,//value is generated on insert
// COMPUTED,//value is generated on insert and update
COMPUTED,//value is generated on insert and update
;
}
}