package org.nd4j.bytebuddy.arrays.assign; import net.bytebuddy.description.method.MethodDescription; import net.bytebuddy.implementation.Implementation; import net.bytebuddy.implementation.bytecode.ByteCodeAppender; import net.bytebuddy.implementation.bytecode.StackManipulation; import net.bytebuddy.implementation.bytecode.collection.ArrayAccess; import net.bytebuddy.implementation.bytecode.constant.IntegerConstant; import net.bytebuddy.implementation.bytecode.member.MethodReturn; import net.bytebuddy.implementation.bytecode.member.MethodVariableAccess; import net.bytebuddy.jar.asm.MethodVisitor; import net.bytebuddy.pool.TypePool; /** * Handles loading the proper index * To assign an element to an array the byte code looks like the following: * public static void main(java.lang.String[]); Code: 0: invokestatic #2 // Method returnArr:()[I <- this is our reference 3: astore_1 //store the variable in 1 4: aload_1 //load the actual variable 1 5: iconst_0 push a 0 on the stack (now we're here asking for the index of the array based on the given variable 6: iconst_5 //push a 5 on to the stack (this is the value we want to assign in the array) 7: iastore //do the actual store operation, we don't do this here 8: return } * This is intended to be used with the following method signature: * void(int[] arr,int index,int value) * * @author Adam Gibson */ public class AssignArrayValueAppender implements ByteCodeAppender { private int index; private int newVal; private static TypePool typePool = TypePool.Default.ofClassPath(); /** * * @param index the index to enqueue * @param newVal the new value to assign to * the index in the array */ public AssignArrayValueAppender(int index, int newVal) { this.index = index; this.newVal = newVal; } @Override public Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext, MethodDescription instrumentedMethod) { //initialize the stack with the array access with this as reference 0 and the array (first argument) as reference 1 StackManipulation compound = assignOperation(); StackManipulation.Size size = compound.apply(methodVisitor, implementationContext); //resolve the type to store in the array and retrieve the store command StackManipulation store = ArrayAccess.of(typePool.describe("int").resolve()).store(); size = size.aggregate(store.apply(methodVisitor, implementationContext)); //set the return type (ALWAYS REMEMBER TO DO THIS) StackManipulation returnOp = MethodReturn.VOID; size = size.aggregate(returnOp.apply(methodVisitor, implementationContext)); return new Size(size.getMaximalSize(), instrumentedMethod.getStackSize()); } public StackManipulation assignOperation() { //enqueue the new value as the item to set StackManipulation arg0 = MethodVariableAccess.REFERENCE.loadOffset(1); //load the value to be assigned StackManipulation val = IntegerConstant.forValue(newVal); //load the index StackManipulation indexToAssign = IntegerConstant.forValue(index); //set the return type StackManipulation.Compound compound = new StackManipulation.Compound(arg0, indexToAssign, val); return compound; } }