Example usage for org.objectweb.asm Type INT_TYPE

List of usage examples for org.objectweb.asm Type INT_TYPE

Introduction

In this page you can find the example usage for org.objectweb.asm Type INT_TYPE.

Prototype

Type INT_TYPE

To view the source code for org.objectweb.asm Type INT_TYPE.

Click Source Link

Document

The int type.

Usage

From source file:boilerplate.processor.adapters.EqualsGenerators.java

License:Open Source License

private static final List<BytecodeGenerator> createGeneratorList() {
    BytecodeGenerator[] generators = { new Int32Generator(Type.BOOLEAN_TYPE),
            new Int32Generator(Type.CHAR_TYPE), new Int32Generator(Type.INT_TYPE),
            new Int32Generator(Type.SHORT_TYPE), new Int32Generator(Type.BYTE_TYPE), new LongGenerator(),
            new FloatGenerator(), new DoubleGenerator(), new ArraysGenerator(), new ObjectGenerator(), };

    List<BytecodeGenerator> list = Arrays.asList(generators);
    return Collections.unmodifiableList(list);
}

From source file:boilerplate.processor.adapters.ToStringMethodInsertion.java

License:Open Source License

private static List<BytecodeGenerator> createMethodList() {
    final Type objectType = Type.getType(Object.class);
    class ObjectMethodInsn extends ToStringMethodInsertion {
        ObjectMethodInsn() {/*from w  w w  .j a  v  a2s  .c  o  m*/
            super(objectType, "appendObject",
                    "(Ljava/lang/StringBuilder;Ljava/lang/String;Ljava/lang/Object;)V");
        }

        @Override
        public boolean matches(Type type) {
            return true;
        }
    }

    BytecodeGenerator[] arr = {
            new ToStringMethodInsertion(Type.BOOLEAN_TYPE, "appendBoolean",
                    "(Ljava/lang/StringBuilder;Ljava/lang/String;Z)V"),
            new ToStringMethodInsertion(Type.BYTE_TYPE, "appendByte",
                    "(Ljava/lang/StringBuilder;Ljava/lang/String;B)V"),
            new ToStringMethodInsertion(Type.CHAR_TYPE, "appendChar",
                    "(Ljava/lang/StringBuilder;Ljava/lang/String;C)V"),
            new ToStringMethodInsertion(Type.DOUBLE_TYPE, "appendDouble",
                    "(Ljava/lang/StringBuilder;Ljava/lang/String;D)V"),
            new ToStringMethodInsertion(Type.FLOAT_TYPE, "appendFloat",
                    "(Ljava/lang/StringBuilder;Ljava/lang/String;F)V"),
            new ToStringMethodInsertion(Type.INT_TYPE, "appendInt",
                    "(Ljava/lang/StringBuilder;Ljava/lang/String;I)V"),
            new ToStringMethodInsertion(Type.LONG_TYPE, "appendLong",
                    "(Ljava/lang/StringBuilder;Ljava/lang/String;J)V"),
            new ToStringMethodInsertion(Type.SHORT_TYPE, "appendShort",
                    "(Ljava/lang/StringBuilder;Ljava/lang/String;S)V"),
            // default
            new ObjectMethodInsn(), };
    List<BytecodeGenerator> list = Arrays.asList(arr);
    return Collections.unmodifiableList(list);
}

From source file:cl.inria.stiq.instrumenter.BCIUtils.java

License:Open Source License

public static Type getTypeForSig(char aSig) {
    switch (aSig) {
    case 'I':
        return Type.INT_TYPE;
    case 'J':
        return Type.LONG_TYPE;
    case 'F':
        return Type.FLOAT_TYPE;
    case 'D':
        return Type.DOUBLE_TYPE;
    case 'L':
        return TYPE_OBJECTID;
    default:/*from w  w w. j  a  va  2 s  . c o  m*/
        throw new RuntimeException("Not handled: " + aSig);
    }
}

From source file:co.cask.cdap.internal.io.DatumWriterGenerator.java

License:Apache License

/**
 * Generates method body for encoding Collection value. The logic is like this:
 *
 * <pre>//  w  ww  .  j  a  va2 s.  c  o m
 * {@code
 *
 * encoder.writeInt(collection.size());
 * for (T element : collection) {
 *   encodeElement(element, encoder, elementSchema, seenRefs);
 * }
 * if (collection.size() > 0) {
 *   encoder.writeInt(0);
 * }
 * }
 * </pre>
 * @param mg
 * @param componentType
 * @param componentSchema
 * @param value
 * @param encoder
 */
private void encodeCollection(GeneratorAdapter mg, TypeToken<?> componentType, Schema componentSchema,
        int value, int encoder, int schemaLocal, int seenRefs) {
    // Encode and store the collection length locally
    mg.loadArg(value);
    mg.invokeInterface(Type.getType(Collection.class), getMethod(int.class, "size"));
    int length = mg.newLocal(Type.INT_TYPE);
    mg.storeLocal(length);

    mg.loadArg(encoder);
    mg.loadLocal(length);
    mg.invokeInterface(Type.getType(Encoder.class), getMethod(Encoder.class, "writeInt", int.class));
    mg.pop();

    // Store the component schema
    mg.loadArg(schemaLocal);
    mg.invokeVirtual(Type.getType(Schema.class), getMethod(Schema.class, "getComponentSchema"));
    int componentSchemaLocal = mg.newLocal(Type.getType(Schema.class));
    mg.storeLocal(componentSchemaLocal);

    // Store the iterator
    int iterator = mg.newLocal(Type.getType(Iterator.class));
    mg.loadArg(value);
    mg.invokeInterface(Type.getType(Collection.class), getMethod(Iterator.class, "iterator"));
    mg.storeLocal(iterator);

    // For loop with iterator. Encode each component
    Label beginFor = mg.mark();
    Label endFor = mg.newLabel();
    mg.loadLocal(iterator);
    mg.invokeInterface(Type.getType(Iterator.class), getMethod(boolean.class, "hasNext"));
    mg.ifZCmp(GeneratorAdapter.EQ, endFor);

    // Call the encode method for encoding the element.
    mg.loadThis();

    mg.loadLocal(iterator);
    mg.invokeInterface(Type.getType(Iterator.class), getMethod(Object.class, "next"));
    doCast(mg, componentType, componentSchema);
    mg.loadArg(encoder);
    mg.loadLocal(componentSchemaLocal);
    mg.loadArg(seenRefs);
    mg.invokeVirtual(classType, getEncodeMethod(componentType, componentSchema));
    mg.goTo(beginFor);

    mg.mark(endFor);

    // if length > 0, write out 0 at the end of array.
    Label zeroLength = mg.newLabel();
    mg.loadLocal(length);
    mg.ifZCmp(GeneratorAdapter.LE, zeroLength);
    encodeInt(mg, 0, encoder);
    mg.mark(zeroLength);
}

From source file:co.cask.cdap.internal.io.DatumWriterGenerator.java

License:Apache License

/**
 * Generates method body for encoding array value. The logic is similar to the one in
 * {@link #encodeCollection}, with collection size replaced with array length.
 *
 * @param mg/*from  w  w w . j av a  2 s.  c o m*/
 * @param componentType
 * @param componentSchema
 * @param value
 * @param encoder
 * @param schemaLocal
 * @param seenRefs
 */
private void encodeArray(GeneratorAdapter mg, TypeToken<?> componentType, Schema componentSchema, int value,
        int encoder, int schemaLocal, int seenRefs) {
    // Encode and store the array length locally
    mg.loadArg(value);
    mg.arrayLength();
    int length = mg.newLocal(Type.INT_TYPE);
    mg.storeLocal(length);

    mg.loadArg(encoder);
    mg.loadLocal(length);
    mg.invokeInterface(Type.getType(Encoder.class), getMethod(Encoder.class, "writeInt", int.class));
    mg.pop();

    // Store the component schema
    mg.loadArg(schemaLocal);
    mg.invokeVirtual(Type.getType(Schema.class), getMethod(Schema.class, "getComponentSchema"));
    int componentSchemaLocal = mg.newLocal(Type.getType(Schema.class));
    mg.storeLocal(componentSchemaLocal);

    // for (int idx = 0; idx < array.length; idx++)
    mg.push(0);
    int idx = mg.newLocal(Type.INT_TYPE);
    mg.storeLocal(idx);
    Label beginFor = mg.mark();
    Label endFor = mg.newLabel();
    mg.loadLocal(idx);
    mg.loadLocal(length);
    mg.ifICmp(GeneratorAdapter.GE, endFor);

    // Call encode method to encode array[idx]
    mg.loadThis();
    mg.loadArg(value);
    mg.loadLocal(idx);
    TypeToken<?> callTypeToken = getCallTypeToken(componentType, componentSchema);
    mg.arrayLoad(Type.getType(callTypeToken.getRawType()));
    mg.loadArg(encoder);
    mg.loadLocal(componentSchemaLocal);
    mg.loadArg(seenRefs);
    mg.invokeVirtual(classType, getEncodeMethod(componentType, componentSchema));

    mg.iinc(idx, 1);
    mg.goTo(beginFor);
    mg.mark(endFor);

    // if length > 0, write out 0 at the end of array.
    Label zeroLength = mg.newLabel();
    mg.loadLocal(length);
    mg.ifZCmp(GeneratorAdapter.LE, zeroLength);
    encodeInt(mg, 0, encoder);
    mg.mark(zeroLength);
}

From source file:co.cask.cdap.internal.io.DatumWriterGenerator.java

License:Apache License

/**
 * Generates method body for encoding map value. The logic is like this:
 *
 * <pre>/*www  .java2  s . co m*/
 * {@code
 *
 * encoder.writeInt(map.size();
 *
 * for (Map.Entry<Key, Value> entry : map.entrySet()) {
 *   encodeKey(entry.getKey(), encoder, keySchema, seenRefs);
 *   encodeValue(entry.getValue(), encoder, valueSchema, seenRefs);
 * }
 *
 * if (map.size() > 0) {
 *   encoder.writeInt(0);
 * }
 * }
 * </pre>
 *
 * @param mg
 * @param keyType
 * @param valueType
 * @param keySchema
 * @param valueSchema
 * @param value
 * @param encoder
 * @param schemaLocal
 * @param seenRefs
 */
private void encodeMap(GeneratorAdapter mg, TypeToken<?> keyType, TypeToken<?> valueType, Schema keySchema,
        Schema valueSchema, int value, int encoder, int schemaLocal, int seenRefs) {
    // Encode and store the map length locally
    mg.loadArg(value);
    mg.invokeInterface(Type.getType(Map.class), getMethod(int.class, "size"));
    int length = mg.newLocal(Type.INT_TYPE);
    mg.storeLocal(length);

    mg.loadArg(encoder);
    mg.loadLocal(length);
    mg.invokeInterface(Type.getType(Encoder.class), getMethod(Encoder.class, "writeInt", int.class));
    mg.pop();

    // Stores the key and value schema
    mg.loadArg(schemaLocal);
    mg.invokeVirtual(Type.getType(Schema.class), getMethod(Map.Entry.class, "getMapSchema"));
    mg.dup();

    int keySchemaLocal = mg.newLocal(Type.getType(Schema.class));
    mg.invokeInterface(Type.getType(Map.Entry.class), getMethod(Object.class, "getKey"));
    mg.checkCast(Type.getType(Schema.class));
    mg.storeLocal(keySchemaLocal);

    int valueSchemaLocal = mg.newLocal(Type.getType(Schema.class));
    mg.invokeInterface(Type.getType(Map.Entry.class), getMethod(Object.class, "getValue"));
    mg.checkCast(Type.getType(Schema.class));
    mg.storeLocal(valueSchemaLocal);

    // Store the entry set iterator
    int iterator = mg.newLocal(Type.getType(Iterator.class));
    mg.loadArg(value);
    mg.invokeInterface(Type.getType(Map.class), getMethod(Set.class, "entrySet"));
    mg.invokeInterface(Type.getType(Set.class), getMethod(Iterator.class, "iterator"));
    mg.storeLocal(iterator);

    // For loop the entry set iterator, encode each key-value pairs
    Label beginFor = mg.mark();
    Label endFor = mg.newLabel();
    mg.loadLocal(iterator);
    mg.invokeInterface(Type.getType(Iterator.class), getMethod(boolean.class, "hasNext"));
    mg.ifZCmp(GeneratorAdapter.EQ, endFor);

    int entry = mg.newLocal(Type.getType(Map.Entry.class));
    mg.loadLocal(iterator);
    mg.invokeInterface(Type.getType(Iterator.class), getMethod(Object.class, "next"));
    mg.checkCast(Type.getType(Map.Entry.class));
    mg.storeLocal(entry);

    // encode key
    mg.loadThis();
    mg.loadLocal(entry);
    mg.invokeInterface(Type.getType(Map.Entry.class), getMethod(Object.class, "getKey"));
    doCast(mg, keyType, keySchema);
    mg.loadArg(encoder);
    mg.loadLocal(keySchemaLocal);
    mg.loadArg(seenRefs);
    mg.invokeVirtual(classType, getEncodeMethod(keyType, keySchema));

    // encode value
    mg.loadThis();
    mg.loadLocal(entry);
    mg.invokeInterface(Type.getType(Map.Entry.class), getMethod(Object.class, "getValue"));
    doCast(mg, valueType, valueSchema);
    mg.loadArg(encoder);
    mg.loadLocal(valueSchemaLocal);
    mg.loadArg(seenRefs);
    mg.invokeVirtual(classType, getEncodeMethod(valueType, valueSchema));

    mg.goTo(beginFor);
    mg.mark(endFor);

    // if length > 0, write out 0 at the end of map
    Label zeroLength = mg.newLabel();
    mg.loadLocal(length);
    mg.ifZCmp(GeneratorAdapter.LE, zeroLength);
    encodeInt(mg, 0, encoder);
    mg.mark(zeroLength);
}

From source file:com.android.build.gradle.internal.incremental.ByteCodeUtils.java

License:Apache License

/**
 * Given a *STORE opcode, it returns the type associated to the variable, or null if
 * not a valid opcode.// w w w . j ava  2 s.c om
 */
static Type getTypeForStoreOpcode(int opcode) {
    switch (opcode) {
    case Opcodes.ISTORE:
        return Type.INT_TYPE;
    case Opcodes.LSTORE:
        return Type.LONG_TYPE;
    case Opcodes.FSTORE:
        return Type.FLOAT_TYPE;
    case Opcodes.DSTORE:
        return Type.DOUBLE_TYPE;
    case Opcodes.ASTORE:
        return Type.getType(Object.class);
    }
    return null;
}

From source file:com.android.build.gradle.internal.incremental.ByteCodeUtilsTest.java

License:Apache License

@Test
public void testIntUnbox() {
    ByteCodeUtils.unbox(generator, Type.INT_TYPE);
    verify(generator, times(1)).unbox(Type.INT_TYPE);
}

From source file:com.android.build.gradle.internal.incremental.ConstructorBuilder.java

License:Apache License

/**
 * Splits the constructor in two methods, the "set up" and the "body" parts (see above).
 *///from w  w w.  j a v  a 2s.c  om
@NonNull
private static Constructor split(@NonNull String owner, @NonNull MethodNode method,
        @NonNull VarInsnNode loadThis, @NonNull MethodInsnNode delegation, int loadThisLine,
        @NonNull List<LocalVariable> variables, int localsAtLoadThis) {
    String[] exceptions = ((List<String>) method.exceptions).toArray(new String[method.exceptions.size()]);

    // Do not add the local array yet, as we treat it as a new variable.
    String newDesc = method.desc.replace(")V", ")Ljava/lang/Object;");
    newDesc = newDesc.replace("(", "([L" + owner + ";");

    Type[] argumentTypes = Type.getArgumentTypes(newDesc);

    // Store the non hotswappable part of the constructor
    List<AbstractInsnNode> fixed = Lists.newLinkedList();
    AbstractInsnNode insn = method.instructions.getFirst();
    while (insn != loadThis) {
        fixed.add(insn);
        insn = insn.getNext();
    }
    fixed.add(loadThis);

    MethodNode initArgs = new MethodNode(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "init$args", newDesc, null,
            exceptions);
    GeneratorAdapter mv = new GeneratorAdapter(initArgs, initArgs.access, initArgs.name, initArgs.desc);
    int newArgument = mv.newLocal(Type.getType("[Ljava/lang/Object;"));

    mv.loadLocal(newArgument);
    ByteCodeUtils.restoreVariables(mv, variables.subList(0, localsAtLoadThis));

    // Now insert the original method
    insn = loadThis.getNext();
    while (insn != delegation) {
        insn.accept(mv);
        insn = insn.getNext();
    }
    LabelNode labelBefore = new LabelNode();
    labelBefore.accept(mv);

    // Create the args array with the local variables and the values to send to the delegated constructor
    Type[] returnTypes = Type.getArgumentTypes(delegation.desc);
    // The extra elements for the local variables and the qualified name of the constructor.
    mv.push(returnTypes.length + 2);
    mv.newArray(Type.getType(Object.class));
    int args = mv.newLocal(Type.getType("[Ljava/lang/Object;"));
    mv.storeLocal(args);
    for (int i = returnTypes.length - 1; i >= 0; i--) {
        Type type = returnTypes[i];
        mv.loadLocal(args);
        mv.swap(type, Type.getType(Object.class));
        mv.push(i + 2);
        mv.swap(type, Type.INT_TYPE);
        mv.box(type);
        mv.arrayStore(Type.getType(Object.class));
    }

    // Store the qualified name of the constructor in the second element of the array.
    mv.loadLocal(args);
    mv.push(1);
    mv.push(delegation.owner + "." + delegation.desc); // Name of the constructor to be called.
    mv.arrayStore(Type.getType(Object.class));

    // Create the locals array and place it in the first element of the return array
    mv.loadLocal(args);
    mv.push(0);
    mv.push(argumentTypes.length + 1);
    mv.newArray(Type.getType(Object.class));
    ByteCodeUtils.loadVariableArray(mv, ByteCodeUtils.toLocalVariables(Arrays.asList(argumentTypes)), 0);

    mv.dup();
    mv.push(argumentTypes.length);
    ByteCodeUtils.newVariableArray(mv, variables);
    mv.arrayStore(Type.getType(Object.class));

    mv.arrayStore(Type.getType(Object.class));

    mv.loadLocal(args);
    mv.returnValue();

    // Move the first variable up to be an argument
    initArgs.desc = initArgs.desc.replace(")", "[Ljava/lang/Object;)");

    newDesc = method.desc.replace("(", "(L" + owner + ";");
    MethodNode body = new MethodNode(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "init$body", newDesc, null,
            exceptions);
    mv = new GeneratorAdapter(body, body.access, body.name, body.desc);
    newArgument = mv.newLocal(Type.getType("[Ljava/lang/Object;"));

    LabelNode labelAfter = new LabelNode();
    labelAfter.accept(body);
    Set<LabelNode> bodyLabels = new HashSet<LabelNode>();

    mv.loadLocal(newArgument);
    ByteCodeUtils.restoreVariables(mv, variables);

    insn = delegation.getNext();
    while (insn != null) {
        if (insn instanceof LabelNode) {
            bodyLabels.add((LabelNode) insn);
        }
        insn.accept(mv);
        insn = insn.getNext();
    }

    // manually transfer the exception table from the existing constructor to the new
    // "init$body" method. The labels were transferred just above so we can reuse them.

    //noinspection unchecked
    for (TryCatchBlockNode tryCatch : (List<TryCatchBlockNode>) method.tryCatchBlocks) {
        tryCatch.accept(mv);
    }

    //noinspection unchecked
    for (LocalVariableNode variable : (List<LocalVariableNode>) method.localVariables) {
        boolean startsInBody = bodyLabels.contains(variable.start);
        boolean endsInBody = bodyLabels.contains(variable.end);
        if (!startsInBody && !endsInBody) {
            if (variable.index != 0) { // '#0' on init$args is not 'this'
                variable.accept(initArgs);
            }
        } else if (startsInBody && endsInBody) {
            variable.accept(body);
        } else if (!startsInBody && endsInBody) {
            // The variable spans from the args to the end of the method, create two:
            if (variable.index != 0) { // '#0' on init$args is not 'this'
                LocalVariableNode var0 = new LocalVariableNode(variable.name, variable.desc, variable.signature,
                        variable.start, labelBefore, variable.index);
                var0.accept(initArgs);
            }
            LocalVariableNode var1 = new LocalVariableNode(variable.name, variable.desc, variable.signature,
                    labelAfter, variable.end, variable.index);
            var1.accept(body);
        } else {
            throw new IllegalStateException("Local variable starts after it ends.");
        }
    }
    // Move the first variable up to be an argument
    body.desc = body.desc.replace(")", "[Ljava/lang/Object;)");

    return new Constructor(owner, fixed, loadThis, loadThisLine, initArgs, delegation, body, variables,
            localsAtLoadThis);
}

From source file:com.android.build.gradle.internal.incremental.ConstructorDelegationDetector.java

License:Apache License

/**
 * Splits the constructor in two methods, the "set up" and the "body" parts (see above).
 *//*from   www  .  j  a  v a 2  s . c o m*/
@NonNull
private static Constructor split(@NonNull String owner, @NonNull MethodNode method,
        @NonNull VarInsnNode loadThis, @NonNull MethodInsnNode delegation, int loadThisLine) {
    String[] exceptions = ((List<String>) method.exceptions).toArray(new String[method.exceptions.size()]);
    String newDesc = method.desc.replaceAll("\\((.*)\\)V", "([Ljava/lang/Object;$1)Ljava/lang/Object;");

    MethodNode initArgs = new MethodNode(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "init$args", newDesc, null,
            exceptions);
    AbstractInsnNode insn = loadThis.getNext();
    while (insn != delegation) {
        insn.accept(initArgs);
        insn = insn.getNext();
    }
    LabelNode labelBefore = new LabelNode();
    labelBefore.accept(initArgs);

    GeneratorAdapter mv = new GeneratorAdapter(initArgs, initArgs.access, initArgs.name, initArgs.desc);
    // Copy the arguments back to the argument array
    // The init_args part cannot access the "this" object and can have side effects on the
    // local variables. Because of this we use the first argument (which we want to keep
    // so all the other arguments remain unchanged) as a reference to the array where to
    // return the values of the modified local variables.
    Type[] types = Type.getArgumentTypes(initArgs.desc);
    int stack = 1; // Skip the first one which is a reference to the local array.
    for (int i = 1; i < types.length; i++) {
        Type type = types[i];
        // This is not this, but the array of local arguments final values.
        mv.visitVarInsn(Opcodes.ALOAD, 0);
        mv.push(i);
        mv.visitVarInsn(type.getOpcode(Opcodes.ILOAD), stack);
        mv.box(type);
        mv.arrayStore(Type.getType(Object.class));
        stack += type.getSize();
    }
    // Create the args array with the values to send to the delegated constructor
    Type[] returnTypes = Type.getArgumentTypes(delegation.desc);
    // The extra element for the qualified name of the constructor.
    mv.push(returnTypes.length + 1);
    mv.newArray(Type.getType(Object.class));
    int args = mv.newLocal(Type.getType("[Ljava/lang/Object;"));
    mv.storeLocal(args);
    for (int i = returnTypes.length - 1; i >= 0; i--) {
        Type type = returnTypes[i];
        mv.loadLocal(args);
        mv.swap(type, Type.getType(Object.class));
        mv.push(i + 1);
        mv.swap(type, Type.INT_TYPE);
        mv.box(type);
        mv.arrayStore(Type.getType(Object.class));
    }

    // Store the qualified name of the constructor in the first element of the array.
    mv.loadLocal(args);
    mv.push(0);
    mv.push(delegation.owner + "." + delegation.desc); // Name of the constructor to be called.
    mv.arrayStore(Type.getType(Object.class));

    mv.loadLocal(args);
    mv.returnValue();

    newDesc = method.desc.replace("(", "(L" + owner + ";");
    MethodNode body = new MethodNode(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "init$body", newDesc, null,
            exceptions);
    LabelNode labelAfter = new LabelNode();
    labelAfter.accept(body);
    Set<LabelNode> bodyLabels = new HashSet<LabelNode>();

    insn = delegation.getNext();
    while (insn != null) {
        if (insn instanceof LabelNode) {
            bodyLabels.add((LabelNode) insn);
        }
        insn.accept(body);
        insn = insn.getNext();
    }

    // manually transfer the exception table from the existing constructor to the new
    // "init$body" method. The labels were transferred just above so we can reuse them.

    //noinspection unchecked
    for (TryCatchBlockNode tryCatch : (List<TryCatchBlockNode>) method.tryCatchBlocks) {
        tryCatch.accept(body);
    }

    //noinspection unchecked
    for (LocalVariableNode variable : (List<LocalVariableNode>) method.localVariables) {
        boolean startsInBody = bodyLabels.contains(variable.start);
        boolean endsInBody = bodyLabels.contains(variable.end);
        if (!startsInBody && !endsInBody) {
            if (variable.index != 0) { // '#0' on init$args is not 'this'
                variable.accept(initArgs);
            }
        } else if (startsInBody && endsInBody) {
            variable.accept(body);
        } else if (!startsInBody && endsInBody) {
            // The variable spans from the args to the end of the method, create two:
            if (variable.index != 0) { // '#0' on init$args is not 'this'
                LocalVariableNode var0 = new LocalVariableNode(variable.name, variable.desc, variable.signature,
                        variable.start, labelBefore, variable.index);
                var0.accept(initArgs);
            }
            LocalVariableNode var1 = new LocalVariableNode(variable.name, variable.desc, variable.signature,
                    labelAfter, variable.end, variable.index);
            var1.accept(body);
        } else {
            throw new IllegalStateException("Local variable starts after it ends.");
        }
    }

    return new Constructor(loadThis, loadThisLine, initArgs, delegation, body);
}