Skip to content

Instantly share code, notes, and snippets.

@Col-E
Created January 23, 2020 08:23
Show Gist options
  • Save Col-E/05f74bd0ee6f5716a394e0cb6c615667 to your computer and use it in GitHub Desktop.
Save Col-E/05f74bd0ee6f5716a394e0cb6c615667 to your computer and use it in GitHub Desktop.
Simulation Draft
package sim;
import java.util.Stack;
/**
* Method invoke context.
*/
public class Context {
private final VirtualValue<?>[] locals;
private final Stack<VirtualValue<?>> stack = new Stack<>();
private final Context parent;
private final VirtualMethod method;
public Context(Context parent, VirtualMethod method) {
this.locals = new VirtualValue<?>[method.resolve().maxLocals];
this.parent = parent;
this.method = method;
}
/**
* @return Context for the prior method in the call-stack.
*/
public Context getParent() {
return parent;
}
/**
* @return Method this context pertains to.
*/
public VirtualMethod getMethod() {
return method;
}
/**
* @return Local variables.
*/
public VirtualValue<?>[] getLocals() {
return locals;
}
/**
* @return Stack values.
*/
public Stack<VirtualValue<?>> getStack() {
return stack;
}
}
package sim;
/**
* Identifiable member, field or method.
*/
public interface Identifiable {
String getName();
String getDescriptor();
}
package sim;
import org.objectweb.asm.tree.MethodNode;
/**
* Runnable type, implying this type resolves to a method-node and has a class parent.
*/
public interface Invokable extends Identifiable, Resolvable<MethodNode, VirtualClass> {
/**
* @param ctx Starting context.
* @return Return value of method.
*/
default VirtualValue<?> invoke(Context ctx) {
// TODO: Method simulation logic goes here
return null;
}
}
package sim;
import org.objectweb.asm.Type;
public class ObjectFactory {
public static <V> VirtualValue<V> create(String descriptor) {
Type type = Type.getType(descriptor);
if (type.getSort() < Type.ARRAY) {
// primitive, default to 0
return new VirtualValue<V>(type, (V) Integer.valueOf(0));
} else {
// TODO: May want special cases for different types?
// object, default to null
return new VirtualValue<V>(type, null);
}
}
}
package sim;
/**
* Item can resolve links to relevant data types.
*
* @param <R> Type to resolve to.
* @param <P> Resolvable parent type.
*/
public interface Resolvable<R, P> {
P parent();
R resolve();
}
package sim;
/**
* Runs a method in a class.
*/
public class Simulation {
private final VirtualClass startClass;
private final VirtualMethod startMethod;
public Simulation(VirtualClass clazz, VirtualMethod method) {
this.startClass = clazz;
this.startMethod = method;
}
/**
* @param args
* Array of locals to use as the initial context.
* @return Execution result.
*/
public VirtualValue<?> run(VirtualValue<?> ... args) {
Context ctx = new Context(null, startMethod);
int index = 0;
for (VirtualValue<?> arg : args) {
ctx.getLocals()[index] = arg;
index += arg.getType().getSize();
}
return startMethod.invoke(ctx);
}
}
package sim;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.ClassNode;
/**
* Class type wrapper.
*/
public class VirtualClass extends VirtualValue<Object> implements Resolvable<ClassNode, Object> {
private final List<VirtualField<?>> fields = new ArrayList<>();
private final List<VirtualMethod> methods = new ArrayList<>();
public VirtualClass(Type type) {
super(type, null);
// TODO: Populate fields & methods
// - Cache the fetched values so other VirtualClass instances can grab them too
// without having to do a lookup every time
}
public List<VirtualField<?>> getFields() {
return fields;
}
public List<VirtualMethod> getMethods() {
return methods;
}
public Optional<VirtualField<?>> getField(String name, String descriptor) {
return fields.stream()
.filter(vf -> vf.getName().equals(name) && vf.getDescriptor().equals(descriptor))
.findFirst();
}
public Optional<VirtualMethod> getMethod(String name, String descriptor) {
return methods.stream()
.filter(vm -> vm.getName().equals(name) && vm.getDescriptor().equals(descriptor))
.findFirst();
}
@Override
public Object parent() {
return null;
}
@Override
public ClassNode resolve() {
// TODO: Fetch classnode instance
return null;
}
}
package sim;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.FieldNode;
/**
* Field wrapper.
*
* @param <T> Object value type.
*/
public class VirtualField<T> extends VirtualMember<FieldNode> {
private final VirtualValue<T> value;
public VirtualField(VirtualClass owner, String name, String descriptor) {
super(owner, name, descriptor);
this.value = ObjectFactory.create(descriptor);
}
public VirtualValue<T> getValue() {
return value;
}
@Override
public FieldNode resolve() {
ClassNode owner = parent().resolve();
for (FieldNode fn : owner.fields)
if (fn.name.endsWith(getName()) && fn.desc.equals(getDescriptor()))
return fn;
return null;
}
}
package sim;
/**
* Generic member wrapper.
*
* @param <R> Type to resolve to.
*/
public abstract class VirtualMember<R> implements Resolvable<R, VirtualClass>, Identifiable {
private final VirtualClass owner;
private final String name;
private final String descriptor;
public VirtualMember(VirtualClass owner, String name, String descriptor) {
this.owner = owner;
this.name = name;
this.descriptor = descriptor;
}
public VirtualClass getOwner() {
return owner;
}
@Override
public String getName() {
return name;
}
@Override
public String getDescriptor() {
return descriptor;
}
@Override
public VirtualClass parent() {
return owner;
}
}
package sim;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.MethodNode;
/**
* Method wrapper.
*/
public class VirtualMethod extends VirtualMember<MethodNode> implements Invokable {
public VirtualMethod(VirtualClass owner, String name, String descriptor) {
super(owner, name, descriptor);
}
@Override
public MethodNode resolve() {
ClassNode owner = parent().resolve();
for (MethodNode mn : owner.methods)
if (mn.name.endsWith(getName()) && mn.desc.equals(getDescriptor()))
return mn;
return null;
}
}
package sim;
import org.objectweb.asm.Type;
/**
* Value wrapper.
*
* @param <V> Wrapped value type.
*/
public class VirtualValue<V> {
private final Type type;
private V value;
public VirtualValue(Type type, V value) {
this.type = type;
this.value = value;
}
public Type getType() {
return type;
}
public V getValue() {
return value;
}
public void setValue(V value) {
this.value = value;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment