Example usage for org.objectweb.asm Opcodes ALOAD

List of usage examples for org.objectweb.asm Opcodes ALOAD

Introduction

In this page you can find the example usage for org.objectweb.asm Opcodes ALOAD.

Prototype

int ALOAD

To view the source code for org.objectweb.asm Opcodes ALOAD.

Click Source Link

Usage

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()), // []
                    }));
}