List of usage examples for org.objectweb.asm Opcodes ALOAD
int ALOAD
To view the source code for org.objectweb.asm Opcodes ALOAD.
Click Source Link
From source file:com.offbynull.coroutines.instrumenter.asm.InstructionUtils.java
License:Open Source License
/** * Generates instructions to load the local variables table from an object array. * * @param arrayLocalsVar variable that the object array containing local variables table is stored * @param tempObjectVar variable to use for temporary objects * @param frame execution frame at the instruction for which the local variables table is to be restored * @return instructions to load the local variables table from an array * @throws NullPointerException if any argument is {@code null} * @throws IllegalArgumentException if variables have the same index, or if variables have been released, or if variables are of wrong * type/* w w w . j ava2 s . c o m*/ */ public static InsnList loadLocalVariableTable(Variable arrayLocalsVar, Variable tempObjectVar, Frame<BasicValue> frame) { Validate.notNull(arrayLocalsVar); Validate.notNull(tempObjectVar); Validate.notNull(frame); Validate.isTrue(arrayLocalsVar.getType().equals(Type.getType(Object[].class))); Validate.isTrue(tempObjectVar.getType().equals(Type.getType(Object.class))); validateLocalIndicies(arrayLocalsVar.getIndex(), tempObjectVar.getIndex()); InsnList ret = new InsnList(); // Load the locals for (int i = 0; i < frame.getLocals(); i++) { BasicValue basicValue = frame.getLocal(i); Type type = basicValue.getType(); // If type == null, basicValue is pointing to uninitialized var -- basicValue.toString() will return ".". This means that this // slot contains nothing to load. So, skip this slot if we encounter it (such that it will remain uninitialized). if (type == null) { continue; } // If type is 'Lnull;', this means that the slot has been assigned null and that "there has been no merge yet that would 'raise' // the type toward some class or interface type" (from ASM mailing list). We know this slot will always contain null at this // point in the code so there's no specific value to load up from the array. Instead we push a null in to that slot, thereby // keeping the same 'Lnull;' type originally assigned to that slot (it doesn't make sense to do a CHECKCAST because 'null' is // not a real class and can never be a real class -- null is a reserved word in Java). if (type.getSort() == Type.OBJECT && "Lnull;".equals(type.getDescriptor())) { ret.add(new InsnNode(Opcodes.ACONST_NULL)); ret.add(new VarInsnNode(Opcodes.ASTORE, i)); continue; } // Load item from locals storage array ret.add(new VarInsnNode(Opcodes.ALOAD, arrayLocalsVar.getIndex())); ret.add(new LdcInsnNode(i)); ret.add(new InsnNode(Opcodes.AALOAD)); // Convert the item from an object stores it in local vars table. switch (type.getSort()) { case Type.BOOLEAN: ret.add(new TypeInsnNode(Opcodes.CHECKCAST, "java/lang/Boolean")); ret.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z", false)); ret.add(new VarInsnNode(Opcodes.ISTORE, i)); break; case Type.BYTE: ret.add(new TypeInsnNode(Opcodes.CHECKCAST, "java/lang/Byte")); ret.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/lang/Byte", "byteValue", "()B", false)); ret.add(new VarInsnNode(Opcodes.ISTORE, i)); break; case Type.SHORT: ret.add(new TypeInsnNode(Opcodes.CHECKCAST, "java/lang/Short")); ret.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/lang/Short", "shortValue", "()S", false)); ret.add(new VarInsnNode(Opcodes.ISTORE, i)); break; case Type.CHAR: ret.add(new TypeInsnNode(Opcodes.CHECKCAST, "java/lang/Character")); ret.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C", false)); ret.add(new VarInsnNode(Opcodes.ISTORE, i)); break; case Type.INT: ret.add(new TypeInsnNode(Opcodes.CHECKCAST, "java/lang/Integer")); ret.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false)); ret.add(new VarInsnNode(Opcodes.ISTORE, i)); break; case Type.FLOAT: ret.add(new TypeInsnNode(Opcodes.CHECKCAST, "java/lang/Float")); ret.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/lang/Float", "floatValue", "()F", false)); ret.add(new VarInsnNode(Opcodes.FSTORE, i)); break; case Type.LONG: ret.add(new TypeInsnNode(Opcodes.CHECKCAST, "java/lang/Long")); ret.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J", false)); ret.add(new VarInsnNode(Opcodes.LSTORE, i)); break; case Type.DOUBLE: ret.add(new TypeInsnNode(Opcodes.CHECKCAST, "java/lang/Double")); ret.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D", false)); ret.add(new VarInsnNode(Opcodes.DSTORE, i)); break; case Type.ARRAY: case Type.OBJECT: ret.add(new TypeInsnNode(Opcodes.CHECKCAST, basicValue.getType().getInternalName())); ret.add(new VarInsnNode(Opcodes.ASTORE, i)); break; case Type.METHOD: case Type.VOID: default: throw new IllegalStateException(); } } return ret; }
From source file:com.offbynull.coroutines.instrumenter.asm.InstructionUtils.java
License:Open Source License
/** * Generates instructions to save the local variables table to an object array. * * @param arrayLocalsVar variable that the object array containing local variables table is stored * @param tempObjectVar variable to use for temporary objects * @param frame execution frame at the instruction where the local variables table is to be saved * @return instructions to save the local variables table in to an array * @throws NullPointerException if any argument is {@code null} * @throws IllegalArgumentException if variables have the same index, or if variables have been released, or if variables are of wrong * type/*from w w w. j av a 2 s . co m*/ */ public static InsnList saveLocalVariableTable(Variable arrayLocalsVar, Variable tempObjectVar, Frame<BasicValue> frame) { Validate.notNull(arrayLocalsVar); Validate.notNull(tempObjectVar); Validate.notNull(frame); Validate.isTrue(arrayLocalsVar.getType().equals(Type.getType(Object[].class))); Validate.isTrue(tempObjectVar.getType().equals(Type.getType(Object.class))); validateLocalIndicies(arrayLocalsVar.getIndex(), tempObjectVar.getIndex()); InsnList ret = new InsnList(); // Create array and save it in local vars table ret.add(new LdcInsnNode(frame.getLocals())); ret.add(new TypeInsnNode(Opcodes.ANEWARRAY, "java/lang/Object")); ret.add(new VarInsnNode(Opcodes.ASTORE, arrayLocalsVar.getIndex())); // Save the locals for (int i = 0; i < frame.getLocals(); i++) { BasicValue basicValue = frame.getLocal(i); Type type = basicValue.getType(); // If type == null, basicValue is pointing to uninitialized var -- basicValue.toString() will return '.'. This means that this // slot contains nothing to save. So, skip this slot if we encounter it. if (type == null) { continue; } // If type is 'Lnull;', this means that the slot has been assigned null and that "there has been no merge yet that would 'raise' // the type toward some class or interface type" (from ASM mailing list). We know this slot will always contain null at this // point in the code so we can avoid saving it. When we load it back up, we can simply push a null in to that slot, thereby // keeping the same 'Lnull;' type. if ("Lnull;".equals(type.getDescriptor())) { continue; } // Convert the item to an object (if not already an object) and stores it in array. switch (type.getSort()) { case Type.BOOLEAN: ret.add(new VarInsnNode(Opcodes.ILOAD, i)); ret.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;")); ret.add(new VarInsnNode(Opcodes.ASTORE, tempObjectVar.getIndex())); break; case Type.BYTE: ret.add(new VarInsnNode(Opcodes.ILOAD, i)); ret.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;", false)); ret.add(new VarInsnNode(Opcodes.ASTORE, tempObjectVar.getIndex())); break; case Type.SHORT: ret.add(new VarInsnNode(Opcodes.ILOAD, i)); ret.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;", false)); ret.add(new VarInsnNode(Opcodes.ASTORE, tempObjectVar.getIndex())); break; case Type.CHAR: ret.add(new VarInsnNode(Opcodes.ILOAD, i)); ret.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;", false)); ret.add(new VarInsnNode(Opcodes.ASTORE, tempObjectVar.getIndex())); break; case Type.INT: ret.add(new VarInsnNode(Opcodes.ILOAD, i)); ret.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false)); ret.add(new VarInsnNode(Opcodes.ASTORE, tempObjectVar.getIndex())); break; case Type.FLOAT: ret.add(new VarInsnNode(Opcodes.FLOAD, i)); ret.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;", false)); ret.add(new VarInsnNode(Opcodes.ASTORE, tempObjectVar.getIndex())); break; case Type.LONG: ret.add(new VarInsnNode(Opcodes.LLOAD, i)); ret.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;", false)); ret.add(new VarInsnNode(Opcodes.ASTORE, tempObjectVar.getIndex())); break; case Type.DOUBLE: ret.add(new VarInsnNode(Opcodes.DLOAD, i)); ret.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;", false)); ret.add(new VarInsnNode(Opcodes.ASTORE, tempObjectVar.getIndex())); break; case Type.ARRAY: case Type.OBJECT: ret.add(new VarInsnNode(Opcodes.ALOAD, i)); ret.add(new VarInsnNode(Opcodes.ASTORE, tempObjectVar.getIndex())); break; case Type.METHOD: case Type.VOID: default: throw new IllegalStateException(); } // Store item in to locals storage array ret.add(new VarInsnNode(Opcodes.ALOAD, arrayLocalsVar.getIndex())); ret.add(new LdcInsnNode(i)); ret.add(new VarInsnNode(Opcodes.ALOAD, tempObjectVar.getIndex())); ret.add(new InsnNode(Opcodes.AASTORE)); } return ret; }
From source file:com.offbynull.coroutines.instrumenter.generators.GenericGenerators.java
License:Open Source License
/** * Copies a local variable on to the stack. * @param variable variable within the local variable table to load from * @return instructions to load a local variable on to the stack * @throws NullPointerException if any argument is {@code null} * @throws IllegalArgumentException if {@code variable} has been released */// w w w. java 2 s.c om public static InsnList loadVar(Variable variable) { Validate.notNull(variable); InsnList ret = new InsnList(); switch (variable.getType().getSort()) { case Type.BOOLEAN: case Type.BYTE: case Type.CHAR: case Type.SHORT: case Type.INT: ret.add(new VarInsnNode(Opcodes.ILOAD, variable.getIndex())); break; case Type.LONG: ret.add(new VarInsnNode(Opcodes.LLOAD, variable.getIndex())); break; case Type.FLOAT: ret.add(new VarInsnNode(Opcodes.FLOAD, variable.getIndex())); break; case Type.DOUBLE: ret.add(new VarInsnNode(Opcodes.DLOAD, variable.getIndex())); break; case Type.OBJECT: case Type.ARRAY: ret.add(new VarInsnNode(Opcodes.ALOAD, variable.getIndex())); // If required, do it outside this method // ret.add(new TypeInsnNode(Opcodes.CHECKCAST, variable.getType().getInternalName())); break; default: throw new IllegalStateException(); // should never happen, there is code in Variable/VariableTable to make sure invalid // types aren't set } return ret; }
From source file:com.offbynull.coroutines.instrumenter.LocalsStateGenerators.java
License:Open Source License
/** * Generates instructions to load the local variables table. * @param markerType debug marker type/*w w w . j av a 2s . c o m*/ * @param storageVars variables to load locals from * @param frame execution frame at the instruction for which the local variables table is to be restored * @return instructions to load the local variables table from an array * @throws NullPointerException if any argument is {@code null} */ public static InsnList loadLocals(MarkerType markerType, StorageVariables storageVars, Frame<BasicValue> frame) { Validate.notNull(markerType); Validate.notNull(storageVars); Validate.notNull(frame); Variable intsVar = storageVars.getIntStorageVar(); Variable floatsVar = storageVars.getFloatStorageVar(); Variable longsVar = storageVars.getLongStorageVar(); Variable doublesVar = storageVars.getDoubleStorageVar(); Variable objectsVar = storageVars.getObjectStorageVar(); int intsCounter = 0; int floatsCounter = 0; int longsCounter = 0; int doublesCounter = 0; int objectsCounter = 0; InsnList ret = new InsnList(); // Load the locals ret.add(debugMarker(markerType, "Loading locals")); for (int i = 0; i < frame.getLocals(); i++) { BasicValue basicValue = frame.getLocal(i); Type type = basicValue.getType(); // If type == null, basicValue is pointing to uninitialized var -- basicValue.toString() will return ".". This means that this // slot contains nothing to load. So, skip this slot if we encounter it (such that it will remain uninitialized). if (type == null) { ret.add(debugMarker(markerType, "Skipping uninitialized value at " + i)); continue; } // If type is 'Lnull;', this means that the slot has been assigned null and that "there has been no merge yet that would 'raise' // the type toward some class or interface type" (from ASM mailing list). We know this slot will always contain null at this // point in the code so there's no specific value to load up from the array. Instead we push a null in to that slot, thereby // keeping the same 'Lnull;' type originally assigned to that slot (it doesn't make sense to do a CHECKCAST because 'null' is // not a real class and can never be a real class -- null is a reserved word in Java). if (type.getSort() == Type.OBJECT && "Lnull;".equals(type.getDescriptor())) { ret.add(debugMarker(markerType, "Putting null value at " + i)); ret.add(new InsnNode(Opcodes.ACONST_NULL)); ret.add(new VarInsnNode(Opcodes.ASTORE, i)); continue; } // Load the locals switch (type.getSort()) { case Type.BOOLEAN: case Type.BYTE: case Type.SHORT: case Type.CHAR: case Type.INT: ret.add(debugMarker(markerType, "Loading int to LVT index " + i + " from storage index " + intsCounter)); ret.add(new VarInsnNode(Opcodes.ALOAD, intsVar.getIndex())); // [int[]] ret.add(new LdcInsnNode(intsCounter)); // [int[], idx] ret.add(new InsnNode(Opcodes.IALOAD)); // [val] ret.add(new VarInsnNode(Opcodes.ISTORE, i)); // [] intsCounter++; break; case Type.FLOAT: ret.add(debugMarker(markerType, "Loading float to LVT index " + i + " from storage index " + floatsCounter)); ret.add(new VarInsnNode(Opcodes.ALOAD, floatsVar.getIndex())); // [float[]] ret.add(new LdcInsnNode(floatsCounter)); // [float[], idx] ret.add(new InsnNode(Opcodes.FALOAD)); // [val] ret.add(new VarInsnNode(Opcodes.FSTORE, i)); // [] floatsCounter++; break; case Type.LONG: ret.add(debugMarker(markerType, "Loading long to LVT index " + i + " from storage index " + longsCounter)); ret.add(new VarInsnNode(Opcodes.ALOAD, longsVar.getIndex())); // [long[]] ret.add(new LdcInsnNode(longsCounter)); // [long[], idx] ret.add(new InsnNode(Opcodes.LALOAD)); // [val_PART1, val_PART2] ret.add(new VarInsnNode(Opcodes.LSTORE, i)); // [] longsCounter++; break; case Type.DOUBLE: ret.add(debugMarker(markerType, "Loading double to LVT index " + i + " from storage index " + doublesCounter)); ret.add(new VarInsnNode(Opcodes.ALOAD, doublesVar.getIndex())); // [double[]] ret.add(new LdcInsnNode(doublesCounter)); // [double[], idx] ret.add(new InsnNode(Opcodes.DALOAD)); // [val_PART1, val_PART2] ret.add(new VarInsnNode(Opcodes.DSTORE, i)); // [] doublesCounter++; break; case Type.ARRAY: case Type.OBJECT: ret.add(debugMarker(markerType, "Loading object to LVT index " + i + " from storage index " + objectsCounter)); ret.add(new VarInsnNode(Opcodes.ALOAD, objectsVar.getIndex())); // [Object[]] ret.add(new LdcInsnNode(objectsCounter)); // [Object[], idx] ret.add(new InsnNode(Opcodes.AALOAD)); // [val] // must cast, otherwise the jvm won't know the type that's in the localvariable slot and it'll fail when the code tries // to access a method/field on it ret.add(new TypeInsnNode(Opcodes.CHECKCAST, basicValue.getType().getInternalName())); ret.add(new VarInsnNode(Opcodes.ASTORE, i)); // [] objectsCounter++; break; case Type.METHOD: case Type.VOID: default: throw new IllegalStateException(); } } return ret; }
From source file:com.offbynull.coroutines.instrumenter.LocalsStateGenerators.java
License:Open Source License
/** * Generates instructions to save the local variables table. * @param markerType debug marker type/* w w w.ja v a 2s. c o m*/ * @param storageVars variables to store locals in to * @param frame execution frame at the instruction where the local variables table is to be saved * @return instructions to save the local variables table in to an array * @throws NullPointerException if any argument is {@code null} */ public static InsnList saveLocals(MarkerType markerType, StorageVariables storageVars, Frame<BasicValue> frame) { Validate.notNull(markerType); Validate.notNull(storageVars); Validate.notNull(frame); Variable intsVar = storageVars.getIntStorageVar(); Variable floatsVar = storageVars.getFloatStorageVar(); Variable longsVar = storageVars.getLongStorageVar(); Variable doublesVar = storageVars.getDoubleStorageVar(); Variable objectsVar = storageVars.getObjectStorageVar(); int intsCounter = 0; int floatsCounter = 0; int longsCounter = 0; int doublesCounter = 0; int objectsCounter = 0; StorageSizes storageSizes = computeSizes(frame); InsnList ret = new InsnList(); // Create storage arrays and save them in respective storage vars ret.add(merge(debugMarker(markerType, "Saving locals"), mergeIf(intsVar != null, () -> new Object[] { debugMarker(markerType, "Generating ints container (" + storageSizes.getIntsSize() + ")"), new LdcInsnNode(storageSizes.getIntsSize()), new IntInsnNode(Opcodes.NEWARRAY, Opcodes.T_INT), new VarInsnNode(Opcodes.ASTORE, intsVar.getIndex()) }), mergeIf(floatsVar != null, () -> new Object[] { debugMarker(markerType, "Generating floats container (" + storageSizes.getFloatsSize() + ")"), new LdcInsnNode(storageSizes.getFloatsSize()), new IntInsnNode(Opcodes.NEWARRAY, Opcodes.T_FLOAT), new VarInsnNode(Opcodes.ASTORE, floatsVar.getIndex()) }), mergeIf(longsVar != null, () -> new Object[] { debugMarker(markerType, "Generating longs container (" + storageSizes.getLongsSize() + ")"), new LdcInsnNode(storageSizes.getLongsSize()), new IntInsnNode(Opcodes.NEWARRAY, Opcodes.T_LONG), new VarInsnNode(Opcodes.ASTORE, longsVar.getIndex()) }), mergeIf(doublesVar != null, () -> new Object[] { debugMarker(markerType, "Generating doubles container (" + storageSizes.getDoublesSize() + ")"), new LdcInsnNode(storageSizes.getDoublesSize()), new IntInsnNode(Opcodes.NEWARRAY, Opcodes.T_DOUBLE), new VarInsnNode(Opcodes.ASTORE, doublesVar.getIndex()) }), mergeIf(objectsVar != null, () -> new Object[] { debugMarker(markerType, "Generating objects container (" + storageSizes.getObjectsSize() + ")"), new LdcInsnNode(storageSizes.getObjectsSize()), new TypeInsnNode(Opcodes.ANEWARRAY, "java/lang/Object"), new VarInsnNode(Opcodes.ASTORE, objectsVar.getIndex()) }))); // Save the locals for (int i = 0; i < frame.getLocals(); i++) { BasicValue basicValue = frame.getLocal(i); Type type = basicValue.getType(); // If type == null, basicValue is pointing to uninitialized var -- basicValue.toString() will return '.'. This means that this // slot contains nothing to save. So, skip this slot if we encounter it. if (type == null) { ret.add(debugMarker(markerType, "Skipping uninitialized value at " + i)); continue; } // If type is 'Lnull;', this means that the slot has been assigned null and that "there has been no merge yet that would 'raise' // the type toward some class or interface type" (from ASM mailing list). We know this slot will always contain null at this // point in the code so we can avoid saving it. When we load it back up, we can simply push a null in to that slot, thereby // keeping the same 'Lnull;' type. if ("Lnull;".equals(type.getDescriptor())) { ret.add(debugMarker(markerType, "Skipping null value at " + i)); continue; } // Place item in to appropriate storage array switch (type.getSort()) { case Type.BOOLEAN: case Type.BYTE: case Type.SHORT: case Type.CHAR: case Type.INT: ret.add(debugMarker(markerType, "Inserting int at LVT index " + i + " to storage index " + intsCounter)); ret.add(new VarInsnNode(Opcodes.ALOAD, intsVar.getIndex())); // [int[]] ret.add(new LdcInsnNode(intsCounter)); // [int[], idx] ret.add(new VarInsnNode(Opcodes.ILOAD, i)); // [int[], idx, val] ret.add(new InsnNode(Opcodes.IASTORE)); // [] intsCounter++; break; case Type.FLOAT: ret.add(debugMarker(markerType, "Inserting float at LVT index " + i + " to storage index " + floatsCounter)); ret.add(new VarInsnNode(Opcodes.ALOAD, floatsVar.getIndex())); // [float[]] ret.add(new LdcInsnNode(floatsCounter)); // [float[], idx] ret.add(new VarInsnNode(Opcodes.FLOAD, i)); // [float[], idx, val] ret.add(new InsnNode(Opcodes.FASTORE)); // [] floatsCounter++; break; case Type.LONG: ret.add(debugMarker(markerType, "Inserting long at LVT index " + i + " to storage index " + longsCounter)); ret.add(new VarInsnNode(Opcodes.ALOAD, longsVar.getIndex())); // [long[]] ret.add(new LdcInsnNode(longsCounter)); // [long[], idx] ret.add(new VarInsnNode(Opcodes.LLOAD, i)); // [long[], idx, val] ret.add(new InsnNode(Opcodes.LASTORE)); // [] longsCounter++; break; case Type.DOUBLE: ret.add(debugMarker(markerType, "Inserting double at LVT index " + i + " to storage index " + doublesCounter)); ret.add(new VarInsnNode(Opcodes.ALOAD, doublesVar.getIndex())); // [double[]] ret.add(new LdcInsnNode(doublesCounter)); // [double[], idx] ret.add(new VarInsnNode(Opcodes.DLOAD, i)); // [double[], idx, val] ret.add(new InsnNode(Opcodes.DASTORE)); // [] doublesCounter++; break; case Type.ARRAY: case Type.OBJECT: ret.add(debugMarker(markerType, "Inserting object at LVT index " + i + " to storage index " + objectsCounter)); ret.add(new VarInsnNode(Opcodes.ALOAD, objectsVar.getIndex())); // [Object[]] ret.add(new LdcInsnNode(objectsCounter)); // [Object[], idx] ret.add(new VarInsnNode(Opcodes.ALOAD, i)); // [Object[], idx, val] ret.add(new InsnNode(Opcodes.AASTORE)); // [] objectsCounter++; break; case Type.METHOD: case Type.VOID: default: throw new IllegalStateException(); } } return ret; }
From source file:com.offbynull.coroutines.instrumenter.OperandStackStateGenerators.java
License:Open Source License
/** * Generates instructions to load a certain number of items to the top of the operand stack. * @param markerType debug marker type/*w w w . j a v a2 s. c om*/ * @param storageVars variables to load operand stack from * @param frame execution frame at the instruction where the operand stack is to be loaded * @param storageStackStartIdx stack position where {@code storageVars} starts from * @param storageStackLoadIdx stack position where loading should start from * @param count number of stack items to load * @return instructions to load the operand stack from the specified storage variables * @throws NullPointerException if any argument is {@code null} * @throws IllegalArgumentException if any numeric argument is negative, or if you're trying to load stack items that aren't available * in the storage vars (stack items before {@code storageStackStartIdx}), or if you're trying to load too many items on the stack (such * that it goes past {@code frame.getStackSize()}) */ public static InsnList loadOperandStack(MarkerType markerType, StorageVariables storageVars, Frame<BasicValue> frame, int storageStackStartIdx, // stack idx which the storage was started at int storageStackLoadIdx, // stack idx we should start loading at int count) { Validate.notNull(markerType); Validate.notNull(storageVars); Validate.notNull(frame); // no negs allowed Validate.isTrue(storageStackStartIdx >= 0); Validate.isTrue(storageStackLoadIdx >= 0); Validate.isTrue(count >= 0); Validate.isTrue(storageStackLoadIdx >= storageStackStartIdx); Validate.isTrue(storageStackStartIdx + count <= frame.getStackSize()); Validate.isTrue(storageStackStartIdx + count >= 0); // likely will never overflow unless crazy high count passedin, but just in case Variable intsVar = storageVars.getIntStorageVar(); Variable floatsVar = storageVars.getFloatStorageVar(); Variable longsVar = storageVars.getLongStorageVar(); Variable doublesVar = storageVars.getDoubleStorageVar(); Variable objectsVar = storageVars.getObjectStorageVar(); int intsCounter = 0; int floatsCounter = 0; int longsCounter = 0; int doublesCounter = 0; int objectsCounter = 0; InsnList ret = new InsnList(); // Increment offsets for parts of the storage arrays we don't care about. We need to do this so when we load we're loading from the // correct offsets in the storage arrays for (int i = storageStackStartIdx; i < storageStackLoadIdx; i++) { BasicValue basicValue = frame.getStack(i); Type type = basicValue.getType(); // If type is 'Lnull;', this means that the slot has been assigned null and that "there has been no merge yet that would 'raise' // the type toward some class or interface type" (from ASM mailing list). We know this slot will always contain null at this // point in the code so there's no specific value to load up from the array. if (type.getSort() == Type.OBJECT && "Lnull;".equals(type.getDescriptor())) { continue; // skip } switch (type.getSort()) { case Type.BOOLEAN: case Type.BYTE: case Type.SHORT: case Type.CHAR: case Type.INT: intsCounter++; break; case Type.FLOAT: floatsCounter++; break; case Type.LONG: longsCounter++; break; case Type.DOUBLE: doublesCounter++; break; case Type.ARRAY: case Type.OBJECT: objectsCounter++; break; case Type.METHOD: case Type.VOID: default: throw new IllegalArgumentException(); } } // Restore the stack ret.add(debugMarker(markerType, "Loading stack items")); for (int i = storageStackLoadIdx; i < storageStackLoadIdx + count; i++) { BasicValue basicValue = frame.getStack(i); Type type = basicValue.getType(); // If type is 'Lnull;', this means that the slot has been assigned null and that "there has been no merge yet that would 'raise' // the type toward some class or interface type" (from ASM mailing list). We know this slot will always contain null at this // point in the code so there's no specific value to load up from the array. Instead we push a null in to that slot, thereby // keeping the same 'Lnull;' type originally assigned to that slot (it doesn't make sense to do a CHECKCAST because 'null' is // not a real class and can never be a real class -- null is a reserved word in Java). if (type.getSort() == Type.OBJECT && "Lnull;".equals(type.getDescriptor())) { ret.add(debugMarker(markerType, "Loading null value at " + i)); ret.add(new InsnNode(Opcodes.ACONST_NULL)); continue; } // Load item from stack storage array ret.add(debugMarker(markerType, "Loading from container at" + i)); // Convert the item to an object (if not already an object) and stores it in local vars table. Item removed from stack. switch (type.getSort()) { case Type.BOOLEAN: case Type.BYTE: case Type.SHORT: case Type.CHAR: case Type.INT: ret.add(debugMarker(markerType, "Loading int at " + i + " from storage index " + intsCounter)); ret.add(new VarInsnNode(Opcodes.ALOAD, intsVar.getIndex())); // [int[]] ret.add(new LdcInsnNode(intsCounter)); // [int[], idx] ret.add(new InsnNode(Opcodes.IALOAD)); // [val] intsCounter++; break; case Type.FLOAT: ret.add(debugMarker(markerType, "Loading float at " + i + " from storage index " + floatsCounter)); ret.add(new VarInsnNode(Opcodes.ALOAD, floatsVar.getIndex())); // [float[]] ret.add(new LdcInsnNode(floatsCounter)); // [float[], idx] ret.add(new InsnNode(Opcodes.FALOAD)); // [val] floatsCounter++; break; case Type.LONG: ret.add(debugMarker(markerType, "Loading long at " + i + " from storage index " + longsCounter)); ret.add(new VarInsnNode(Opcodes.ALOAD, longsVar.getIndex())); // [long[]] ret.add(new LdcInsnNode(longsCounter)); // [long[], idx] ret.add(new InsnNode(Opcodes.LALOAD)); // [val_PART1, val_PART2] longsCounter++; break; case Type.DOUBLE: ret.add(debugMarker(markerType, "Loading double at " + i + " from storage index " + doublesCounter)); ret.add(new VarInsnNode(Opcodes.ALOAD, doublesVar.getIndex())); // [double[]] ret.add(new LdcInsnNode(doublesCounter)); // [double[], idx] ret.add(new InsnNode(Opcodes.DALOAD)); // [val_PART1, val_PART2] doublesCounter++; break; case Type.ARRAY: case Type.OBJECT: ret.add(debugMarker(markerType, "Loading object at " + i + " from storage index " + objectsCounter)); ret.add(new VarInsnNode(Opcodes.ALOAD, objectsVar.getIndex())); // [Object[]] ret.add(new LdcInsnNode(objectsCounter)); // [Object[], idx] ret.add(new InsnNode(Opcodes.AALOAD)); // [val] ret.add(new TypeInsnNode(Opcodes.CHECKCAST, basicValue.getType().getInternalName())); objectsCounter++; break; case Type.METHOD: case Type.VOID: default: throw new IllegalArgumentException(); } } return ret; }
From source file:com.offbynull.coroutines.instrumenter.OperandStackStateGenerators.java
License:Open Source License
/** * Generates instructions to save a certain number of items from the top of the operand stack. * <p>/* www.ja v a2 s. co m*/ * The instructions generated here expect the operand stack to be fully loaded. The stack items specified by {@code frame} must actually * all be on the operand stack. * <p> * REMEMBER: The items aren't returned to the operand stack after they've been saved (they have been popped off the stack). If you want * them back on the operand stack, reload using * {@code loadOperandStack(markerType, storageVars, frame, frame.getStackSize() - count, frame.getStackSize() - count, count)}. * @param markerType debug marker type * @param storageVars variables to store operand stack in to * @param frame execution frame at the instruction where the operand stack is to be saved * @param count number of items to store from the stack * @return instructions to save the operand stack to the storage variables * @throws NullPointerException if any argument is {@code null} * @throws IllegalArgumentException if {@code size} is larger than the number of items in the stack at {@code frame} (or is negative), * or if {@code count} is larger than {@code top} (or is negative) */ public static InsnList saveOperandStack(MarkerType markerType, StorageVariables storageVars, Frame<BasicValue> frame, int count) { Validate.notNull(markerType); Validate.notNull(storageVars); Validate.notNull(frame); Validate.isTrue(count >= 0); Validate.isTrue(count <= frame.getStackSize()); Variable intsVar = storageVars.getIntStorageVar(); Variable floatsVar = storageVars.getFloatStorageVar(); Variable longsVar = storageVars.getLongStorageVar(); Variable doublesVar = storageVars.getDoubleStorageVar(); Variable objectsVar = storageVars.getObjectStorageVar(); StorageSizes storageSizes = computeSizes(frame, frame.getStackSize() - count, count); int intsCounter = storageSizes.getIntsSize() - 1; int floatsCounter = storageSizes.getFloatsSize() - 1; int longsCounter = storageSizes.getLongsSize() - 1; int doublesCounter = storageSizes.getDoublesSize() - 1; int objectsCounter = storageSizes.getObjectsSize() - 1; InsnList ret = new InsnList(); // Create stack storage arrays and save them ret.add(merge(debugMarker(markerType, "Saving operand stack (" + count + " items)"), mergeIf(storageSizes.getIntsSize() > 0, () -> new Object[] { debugMarker(markerType, "Generating ints container (" + storageSizes.getIntsSize() + ")"), new LdcInsnNode(storageSizes.getIntsSize()), new IntInsnNode(Opcodes.NEWARRAY, Opcodes.T_INT), new VarInsnNode(Opcodes.ASTORE, intsVar.getIndex()) }), mergeIf(storageSizes.getFloatsSize() > 0, () -> new Object[] { debugMarker(markerType, "Generating floats container (" + storageSizes.getFloatsSize() + ")"), new LdcInsnNode(storageSizes.getFloatsSize()), new IntInsnNode(Opcodes.NEWARRAY, Opcodes.T_FLOAT), new VarInsnNode(Opcodes.ASTORE, floatsVar.getIndex()) }), mergeIf(storageSizes.getLongsSize() > 0, () -> new Object[] { debugMarker(markerType, "Generating longs container (" + storageSizes.getLongsSize() + ")"), new LdcInsnNode(storageSizes.getLongsSize()), new IntInsnNode(Opcodes.NEWARRAY, Opcodes.T_LONG), new VarInsnNode(Opcodes.ASTORE, longsVar.getIndex()) }), mergeIf(storageSizes.getDoublesSize() > 0, () -> new Object[] { debugMarker(markerType, "Generating doubles container (" + storageSizes.getDoublesSize() + ")"), new LdcInsnNode(storageSizes.getDoublesSize()), new IntInsnNode(Opcodes.NEWARRAY, Opcodes.T_DOUBLE), new VarInsnNode(Opcodes.ASTORE, doublesVar.getIndex()) }), mergeIf(storageSizes.getObjectsSize() > 0, () -> new Object[] { debugMarker(markerType, "Generating objects container (" + storageSizes.getObjectsSize() + ")"), new LdcInsnNode(storageSizes.getObjectsSize()), new TypeInsnNode(Opcodes.ANEWARRAY, "java/lang/Object"), new VarInsnNode(Opcodes.ASTORE, objectsVar.getIndex()) }))); // Save the stack int start = frame.getStackSize() - 1; int end = frame.getStackSize() - count; for (int i = start; i >= end; i--) { BasicValue basicValue = frame.getStack(i); Type type = basicValue.getType(); // If type is 'Lnull;', this means that the slot has been assigned null and that "there has been no merge yet that would 'raise' // the type toward some class or interface type" (from ASM mailing list). We know this slot will always contain null at this // point in the code so we can avoid saving it (but we still need to do a POP to get rid of it). When we load it back up, we can // simply push a null in to that slot, thereby keeping the same 'Lnull;' type. if ("Lnull;".equals(type.getDescriptor())) { ret.add(debugMarker(markerType, "Skipping null value at " + i)); ret.add(new InsnNode(Opcodes.POP)); continue; } // Convert the item to an object (if not already an object) and stores it in local vars table. Item removed from stack. switch (type.getSort()) { case Type.BOOLEAN: case Type.BYTE: case Type.SHORT: case Type.CHAR: case Type.INT: ret.add(debugMarker(markerType, "Popping/storing int at " + i + " to storage index " + intsCounter)); ret.add(new VarInsnNode(Opcodes.ALOAD, intsVar.getIndex())); // [val, int[]] ret.add(new InsnNode(Opcodes.SWAP)); // [int[], val] ret.add(new LdcInsnNode(intsCounter)); // [int[], val, idx] ret.add(new InsnNode(Opcodes.SWAP)); // [int[], idx, val] ret.add(new InsnNode(Opcodes.IASTORE)); // [] intsCounter--; break; case Type.FLOAT: ret.add(debugMarker(markerType, "Popping/storing float at " + i + " to storage index " + floatsCounter)); ret.add(new VarInsnNode(Opcodes.ALOAD, floatsVar.getIndex())); // [val, float[]] ret.add(new InsnNode(Opcodes.SWAP)); // [float[], val] ret.add(new LdcInsnNode(floatsCounter)); // [float[], val, idx] ret.add(new InsnNode(Opcodes.SWAP)); // [float[], idx, val] ret.add(new InsnNode(Opcodes.FASTORE)); // [] floatsCounter--; break; case Type.LONG: ret.add(debugMarker(markerType, "Popping/storing long at " + i + " to storage index " + longsCounter)); ret.add(new VarInsnNode(Opcodes.ALOAD, longsVar.getIndex())); // [val_PART1, val_PART2, long[]] ret.add(new LdcInsnNode(longsCounter)); // [val_PART1, val_PART2, long[], idx] ret.add(new InsnNode(Opcodes.DUP2_X2)); // [long[], idx, val_PART1, val_PART2, long[], idx] ret.add(new InsnNode(Opcodes.POP2)); // [long[], idx, val_PART1, val_PART2] ret.add(new InsnNode(Opcodes.LASTORE)); // [] longsCounter--; break; case Type.DOUBLE: ret.add(debugMarker(markerType, "Popping/storing double at " + i + " to storage index " + doublesCounter)); ret.add(new VarInsnNode(Opcodes.ALOAD, doublesVar.getIndex())); // [val_PART1, val_PART2, double[]] ret.add(new LdcInsnNode(doublesCounter)); // [val_PART1, val_PART2, double[], idx] ret.add(new InsnNode(Opcodes.DUP2_X2)); // [double[], idx, val_PART1, val_PART2, double[], idx] ret.add(new InsnNode(Opcodes.POP2)); // [double[], idx, val_PART1, val_PART2] ret.add(new InsnNode(Opcodes.DASTORE)); // [] doublesCounter--; break; case Type.ARRAY: case Type.OBJECT: ret.add(debugMarker(markerType, "Popping/storing object at " + i + " to storage index " + objectsCounter)); ret.add(new VarInsnNode(Opcodes.ALOAD, objectsVar.getIndex())); // [val, object[]] ret.add(new InsnNode(Opcodes.SWAP)); // [object[], val] ret.add(new LdcInsnNode(objectsCounter)); // [object[], val, idx] ret.add(new InsnNode(Opcodes.SWAP)); // [object[], idx, val] ret.add(new InsnNode(Opcodes.AASTORE)); // [] objectsCounter--; break; case Type.METHOD: case Type.VOID: default: throw new IllegalArgumentException(); } } // At this point, the storage array will contain the saved operand stack AND THE STACK WILL HAVE count ITEMS POPPED OFF OF IT. // // Reload using... // --------------- // ret.add(debugMarker(markerType, "Reloading stack items")); // InsnList reloadInsnList = loadOperandStack(markerType, storageVars, frame, // frame.getStackSize() - count, // frame.getStackSize() - count, // count); // ret.add(reloadInsnList); return ret; }
From source file:com.offbynull.coroutines.instrumenter.PackStateGenerators.java
License:Open Source License
public static InsnList packStorageArrays(MarkerType markerType, Frame<BasicValue> frame, Variable containerVar, StorageVariables localsStorageVars, StorageVariables operandStackStorageVars) { Validate.notNull(markerType);/* ww w . j a v a 2 s . c o m*/ Validate.notNull(frame); Validate.notNull(containerVar); Validate.notNull(localsStorageVars); Validate.notNull(operandStackStorageVars); Variable localsIntsVar = localsStorageVars.getIntStorageVar(); Variable localsFloatsVar = localsStorageVars.getFloatStorageVar(); Variable localsLongsVar = localsStorageVars.getLongStorageVar(); Variable localsDoublesVar = localsStorageVars.getDoubleStorageVar(); Variable localsObjectsVar = localsStorageVars.getObjectStorageVar(); Variable stackIntsVar = operandStackStorageVars.getIntStorageVar(); Variable stackFloatsVar = operandStackStorageVars.getFloatStorageVar(); Variable stackLongsVar = operandStackStorageVars.getLongStorageVar(); Variable stackDoublesVar = operandStackStorageVars.getDoubleStorageVar(); Variable stackObjectsVar = operandStackStorageVars.getObjectStorageVar(); StorageSizes stackSizes = OperandStackStateGenerators.computeSizes(frame, 0, frame.getStackSize()); StorageSizes localsSizes = LocalsStateGenerators.computeSizes(frame); // Why are we using size > 0 vs checking to see if var != null? // // REMEMBER THAT the analyzer will determine the variable slots to create for storage array based on its scan of EVERY // continuation/suspend point in the method. Imagine the method that we're instrumenting is this... // // public void example(Continuation c, String arg1) { // String var1 = "hi"; // c.suspend(); // // System.out.println(var1); // int var2 = 5; // c.suspend(); // // System.out.println(var1 + var2); // } // // There are two continuation/suspend points. The analyzer determines that method will need to assign variable slots for // localsObjectsVar+localsIntsVar. All the other locals vars will be null. // // If we ended up using var != null instead of size > 0, things would mess up on the first suspend(). The only variable initialized // at the first suspend is var1. As such, LocalStateGenerator ONLY CREATES AN ARRAY FOR localsObjectsVar. It doesn't touch // localsIntsVar because, at the first suspend(), var2 is UNINITALIZED. Nothing has been set to that variable slot. // // // The same thing applies to the operand stack. It doesn't make sense to create arrays for operand stack types that don't exist yet // at a continuation point, even though they may exist at other continuation points furhter down // Storage arrays in to locals container return merge( debugMarker(markerType, "Packing storage arrays for locals and operand stack in to an Object[]"), new LdcInsnNode(10), new TypeInsnNode(Opcodes.ANEWARRAY, "java/lang/Object"), new VarInsnNode(Opcodes.ASTORE, containerVar.getIndex()), mergeIf(localsSizes.getIntsSize() > 0, () -> new Object[] { debugMarker(markerType, "Putting locals ints in to container"), new VarInsnNode(Opcodes.ALOAD, containerVar.getIndex()), // [Object[]] new LdcInsnNode(0), // [Object[], 0] new VarInsnNode(Opcodes.ALOAD, localsIntsVar.getIndex()), // [Object[], 0, val] new InsnNode(Opcodes.AASTORE), // [] }), mergeIf(localsSizes.getFloatsSize() > 0, () -> new Object[] { debugMarker(markerType, "Putting locals floats in to container"), new VarInsnNode(Opcodes.ALOAD, containerVar.getIndex()), // [Object[]] new LdcInsnNode(1), // [Object[], 1] new VarInsnNode(Opcodes.ALOAD, localsFloatsVar.getIndex()), // [Object[], 1, val] new InsnNode(Opcodes.AASTORE), // [] }), mergeIf(localsSizes.getLongsSize() > 0, () -> new Object[] { debugMarker(markerType, "Putting locals longs in to container"), new VarInsnNode(Opcodes.ALOAD, containerVar.getIndex()), // [Object[]] new LdcInsnNode(2), // [Object[], 2] new VarInsnNode(Opcodes.ALOAD, localsLongsVar.getIndex()), // [Object[], 2, val] new InsnNode(Opcodes.AASTORE), // [] }), mergeIf(localsSizes.getDoublesSize() > 0, () -> new Object[] { debugMarker(markerType, "Putting locals doubles in to container"), new VarInsnNode(Opcodes.ALOAD, containerVar.getIndex()), // [Object[]] new LdcInsnNode(3), // [Object[], 3] new VarInsnNode(Opcodes.ALOAD, localsDoublesVar.getIndex()), // [Object[], 3, val] new InsnNode(Opcodes.AASTORE), // [] }), mergeIf(localsSizes.getObjectsSize() > 0, () -> new Object[] { debugMarker(markerType, "Putting locals objects in to container"), new VarInsnNode(Opcodes.ALOAD, containerVar.getIndex()), // [Object[]] new LdcInsnNode(4), // [Object[], 4] new VarInsnNode(Opcodes.ALOAD, localsObjectsVar.getIndex()), // [Object[], 4, val] new InsnNode(Opcodes.AASTORE), // [] }), mergeIf(stackSizes.getIntsSize() > 0, () -> new Object[] { debugMarker(markerType, "Putting stack ints in to container"), new VarInsnNode(Opcodes.ALOAD, containerVar.getIndex()), // [Object[]] new LdcInsnNode(5), // [Object[], 5] new VarInsnNode(Opcodes.ALOAD, stackIntsVar.getIndex()), // [Object[], 5, val] new InsnNode(Opcodes.AASTORE), // [] }), mergeIf(stackSizes.getFloatsSize() > 0, () -> new Object[] { debugMarker(markerType, "Putting stack floats in to container"), new VarInsnNode(Opcodes.ALOAD, containerVar.getIndex()), // [Object[]] new LdcInsnNode(6), // [Object[], 6] new VarInsnNode(Opcodes.ALOAD, stackFloatsVar.getIndex()), // [Object[], 6, val] new InsnNode(Opcodes.AASTORE), // [] }), mergeIf(stackSizes.getLongsSize() > 0, () -> new Object[] { debugMarker(markerType, "Putting stack longs in to container"), new VarInsnNode(Opcodes.ALOAD, containerVar.getIndex()), // [Object[]] new LdcInsnNode(7), // [Object[], 7] new VarInsnNode(Opcodes.ALOAD, stackLongsVar.getIndex()), // [Object[], 7, val] new InsnNode(Opcodes.AASTORE), // [] }), mergeIf(stackSizes.getDoublesSize() > 0, () -> new Object[] { debugMarker(markerType, "Putting stack doubles in to container"), new VarInsnNode(Opcodes.ALOAD, containerVar.getIndex()), // [Object[]] new LdcInsnNode(8), // [Object[], 8] new VarInsnNode(Opcodes.ALOAD, stackDoublesVar.getIndex()), // [Object[], 8, val] new InsnNode(Opcodes.AASTORE), // [] }), mergeIf(stackSizes.getObjectsSize() > 0, () -> new Object[] { debugMarker(markerType, "Putting stack objects in to container"), new VarInsnNode(Opcodes.ALOAD, containerVar.getIndex()), // [Object[]] new LdcInsnNode(9), // [Object[], 9] new VarInsnNode(Opcodes.ALOAD, stackObjectsVar.getIndex()), // [Object[], 9, val] new InsnNode(Opcodes.AASTORE), // [] })); }
From source file:com.offbynull.coroutines.instrumenter.PackStateGenerators.java
License:Open Source License
public static InsnList unpackLocalsStorageArrays(MarkerType markerType, Frame<BasicValue> frame, Variable containerVar, StorageVariables localsStorageVars) { Validate.notNull(markerType);//w w w. ja v a 2 s . c om Validate.notNull(containerVar); Validate.notNull(localsStorageVars); Variable localsIntsVar = localsStorageVars.getIntStorageVar(); Variable localsFloatsVar = localsStorageVars.getFloatStorageVar(); Variable localsLongsVar = localsStorageVars.getLongStorageVar(); Variable localsDoublesVar = localsStorageVars.getDoubleStorageVar(); Variable localsObjectsVar = localsStorageVars.getObjectStorageVar(); StorageSizes localsSizes = LocalsStateGenerators.computeSizes(frame); // Why are we using size > 0 vs checking to see if var != null? // // REMEMBER THAT the analyzer will determine the variable slots to create for storage array based on its scan of EVERY // continuation/suspend point in the method. Imagine the method that we're instrumenting is this... // // public void example(Continuation c, String arg1) { // String var1 = "hi"; // c.suspend(); // // System.out.println(var1); // int var2 = 5; // c.suspend(); // // System.out.println(var1 + var2); // } // // There are two continuation/suspend points. The analyzer determines that method will need to assign variable slots for // localsObjectsVar+localsIntsVar. All the other locals vars will be null. // // If we ended up using var != null instead of size > 0, things would mess up on the first suspend(). The only variable initialized // at the first suspend is var1. As such, LocalStateGenerator ONLY CREATES AN ARRAY FOR localsObjectsVar. It doesn't touch // localsIntsVar because, at the first suspend(), var2 is UNINITALIZED. Nothing has been set to that variable slot. // // // The same thing applies to the operand stack. It doesn't make sense to create arrays for operand stack types that don't exist yet // at a continuation point, even though they may exist at other continuation points furhter down // Storage arrays from locals container return merge( debugMarker(markerType, "Unpacking storage arrays for locals and operand stack from an Object[]"), mergeIf(localsSizes.getIntsSize() > 0, () -> new Object[] { debugMarker(markerType, "Getting locals ints from to container"), new VarInsnNode(Opcodes.ALOAD, containerVar.getIndex()), // [Object[]] new LdcInsnNode(0), // [Object[], 0] new InsnNode(Opcodes.AALOAD), // [val] new TypeInsnNode(Opcodes.CHECKCAST, localsIntsVar.getType().getInternalName()), // [val] REQ BY JVM SO TYPE IS KNOWN new VarInsnNode(Opcodes.ASTORE, localsIntsVar.getIndex()), // [] }), mergeIf(localsSizes.getFloatsSize() > 0, () -> new Object[] { debugMarker(markerType, "Getting locals floats from to container"), new VarInsnNode(Opcodes.ALOAD, containerVar.getIndex()), // [Object[]] new LdcInsnNode(1), // [Object[], 1] new InsnNode(Opcodes.AALOAD), // [val] new TypeInsnNode(Opcodes.CHECKCAST, localsFloatsVar.getType().getInternalName()), // [val] REQ BY JVM SO TYPE IS KNOWN new VarInsnNode(Opcodes.ASTORE, localsFloatsVar.getIndex()), // [] }), mergeIf(localsSizes.getLongsSize() > 0, () -> new Object[] { debugMarker(markerType, "Getting locals longs from to container"), new VarInsnNode(Opcodes.ALOAD, containerVar.getIndex()), // [Object[]] new LdcInsnNode(2), // [Object[], 2] new InsnNode(Opcodes.AALOAD), // [val] new TypeInsnNode(Opcodes.CHECKCAST, localsLongsVar.getType().getInternalName()), // [val] REQ BY JVM SO TYPE IS KNOWN new VarInsnNode(Opcodes.ASTORE, localsLongsVar.getIndex()), // [] }), mergeIf(localsSizes.getDoublesSize() > 0, () -> new Object[] { debugMarker(markerType, "Getting locals doubles from to container"), new VarInsnNode(Opcodes.ALOAD, containerVar.getIndex()), // [Object[]] new LdcInsnNode(3), // [Object[], 3] new InsnNode(Opcodes.AALOAD), // [val] new TypeInsnNode(Opcodes.CHECKCAST, localsDoublesVar.getType().getInternalName()), // [val] REQ BY JVM SO TYPE IS KNOWN new VarInsnNode(Opcodes.ASTORE, localsDoublesVar.getIndex()), // [] }), mergeIf(localsSizes.getObjectsSize() > 0, () -> new Object[] { debugMarker(markerType, "Getting locals objects from to container"), new VarInsnNode(Opcodes.ALOAD, containerVar.getIndex()), // [Object[]] new LdcInsnNode(4), // [Object[], 4] new InsnNode(Opcodes.AALOAD), // [val] new TypeInsnNode(Opcodes.CHECKCAST, localsObjectsVar.getType().getInternalName()), // [val] REQ BY JVM SO TYPE IS KNOWN new VarInsnNode(Opcodes.ASTORE, localsObjectsVar.getIndex()), // [] })); }
From source file:com.offbynull.coroutines.instrumenter.PackStateGenerators.java
License:Open Source License
public static InsnList unpackOperandStackStorageArrays(MarkerType markerType, Frame<BasicValue> frame, Variable containerVar, StorageVariables operandStackStorageVars) { Validate.notNull(markerType);//from w w w. ja v a2 s .c om Validate.notNull(containerVar); Validate.notNull(operandStackStorageVars); Variable stackIntsVar = operandStackStorageVars.getIntStorageVar(); Variable stackFloatsVar = operandStackStorageVars.getFloatStorageVar(); Variable stackLongsVar = operandStackStorageVars.getLongStorageVar(); Variable stackDoublesVar = operandStackStorageVars.getDoubleStorageVar(); Variable stackObjectsVar = operandStackStorageVars.getObjectStorageVar(); StorageSizes stackSizes = OperandStackStateGenerators.computeSizes(frame, 0, frame.getStackSize()); // Why are we using size > 0 vs checking to see if var != null? // // REMEMBER THAT the analyzer will determine the variable slots to create for storage array based on its scan of EVERY // continuation/suspend point in the method. Imagine the method that we're instrumenting is this... // // public void example(Continuation c, String arg1) { // String var1 = "hi"; // c.suspend(); // // System.out.println(var1); // int var2 = 5; // c.suspend(); // // System.out.println(var1 + var2); // } // // There are two continuation/suspend points. The analyzer determines that method will need to assign variable slots for // localsObjectsVar+localsIntsVar. All the other locals vars will be null. // // If we ended up using var != null instead of size > 0, things would mess up on the first suspend(). The only variable initialized // at the first suspend is var1. As such, LocalStateGenerator ONLY CREATES AN ARRAY FOR localsObjectsVar. It doesn't touch // localsIntsVar because, at the first suspend(), var2 is UNINITALIZED. Nothing has been set to that variable slot. // // // The same thing applies to the operand stack. It doesn't make sense to create arrays for operand stack types that don't exist yet // at a continuation point, even though they may exist at other continuation points furhter down // Storage arrays from locals container return merge(debugMarker(markerType, "Unpacking storage arrays for operand stack from an Object[]"), mergeIf(stackSizes.getIntsSize() > 0, () -> new Object[] { debugMarker(markerType, "Getting stack ints from to container"), new VarInsnNode(Opcodes.ALOAD, containerVar.getIndex()), // [Object[]] new LdcInsnNode(5), // [Object[], 5] new InsnNode(Opcodes.AALOAD), // [val] new TypeInsnNode(Opcodes.CHECKCAST, stackIntsVar.getType().getInternalName()), // [val] REQ BY JVM SO TYPE IS KNOWN new VarInsnNode(Opcodes.ASTORE, stackIntsVar.getIndex()), // [] }), mergeIf(stackSizes.getFloatsSize() > 0, () -> new Object[] { debugMarker(markerType, "Getting stack floats from to container"), new VarInsnNode(Opcodes.ALOAD, containerVar.getIndex()), // [Object[]] new LdcInsnNode(6), // [Object[], 6] new InsnNode(Opcodes.AALOAD), // [val] new TypeInsnNode(Opcodes.CHECKCAST, stackFloatsVar.getType().getInternalName()), // [val] REQ BY JVM SO TYPE IS KNOWN new VarInsnNode(Opcodes.ASTORE, stackFloatsVar.getIndex()), // [] }), mergeIf(stackSizes.getLongsSize() > 0, () -> new Object[] { debugMarker(markerType, "Getting stack longs from to container"), new VarInsnNode(Opcodes.ALOAD, containerVar.getIndex()), // [Object[]] new LdcInsnNode(7), // [Object[], 7] new InsnNode(Opcodes.AALOAD), // [val] new TypeInsnNode(Opcodes.CHECKCAST, stackLongsVar.getType().getInternalName()), // [val] REQ BY JVM SO TYPE IS KNOWN new VarInsnNode(Opcodes.ASTORE, stackLongsVar.getIndex()), // [] }), mergeIf(stackSizes.getDoublesSize() > 0, () -> new Object[] { debugMarker(markerType, "Getting stack doubles from to container"), new VarInsnNode(Opcodes.ALOAD, containerVar.getIndex()), // [Object[]] new LdcInsnNode(8), // [Object[], 8] new InsnNode(Opcodes.AALOAD), // [val] new TypeInsnNode(Opcodes.CHECKCAST, stackDoublesVar.getType().getInternalName()), // [val] REQ BY JVM SO TYPE IS KNOWN new VarInsnNode(Opcodes.ASTORE, stackDoublesVar.getIndex()), // [] }), mergeIf(stackSizes.getObjectsSize() > 0, () -> new Object[] { debugMarker(markerType, "Getting stack objects from to container"), new VarInsnNode(Opcodes.ALOAD, containerVar.getIndex()), // [Object[]] new LdcInsnNode(9), // [Object[], 9] new InsnNode(Opcodes.AALOAD), // [val] new TypeInsnNode(Opcodes.CHECKCAST, stackObjectsVar.getType().getInternalName()), // [val] REQ BY JVM SO TYPE IS KNOWN new VarInsnNode(Opcodes.ASTORE, stackObjectsVar.getIndex()), // [] })); }