package org.coldswap.util;
/**
* (C) Copyright 2013 Faur Ioan-Aurel.
* <p/>
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Lesser General Public License
* (LGPL) version 2.1 which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/lgpl-2.1.html
* <p/>
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* <p/>
* Contributors:
* faur
* <p/>
* Created at:
* 3:47 PM 5/5/13
*/
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Label;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.*;
import java.util.HashMap;
import java.util.Map;
/**
* Generates byte code for new classes.
*/
public class ByteCodeGenerator {
private static final Map<LabelNode, LabelNode> labelNodes = new HashMap<LabelNode, LabelNode>();
private static final Map<Label, Label> labels = new HashMap<Label, Label>();
private static final Map<Integer, LabelNode> offset = new HashMap<Integer, LabelNode>();
private static final Map<Label, LabelNode> offsetL = new HashMap<Label, LabelNode>();
private static LabelNode firstLabel = null;
private static LabelNode lastLabel;
/**
* Creates a new class containing the new static field.
*
* @param classNode containing the old class.
* @param fieldNode containing the old field.
* @param initInstructions a list of instructions that goes into <clinit>.
* @param className the name of the new class to be generated.
* @return an array of bytes which builds the new class.
*/
@SuppressWarnings("unchecked")
public static byte[] newFieldClass(ClassNode classNode, FieldNode fieldNode, InsnList initInstructions, String className) {
ClassNode newClass = new ClassNode();
newClass.version = classNode.version;
newClass.access = Opcodes.ACC_PUBLIC;
newClass.signature = "L" + className + ";";
newClass.name = className;
newClass.superName = "java/lang/Object";
newClass.fields.add(new FieldNode(fieldNode.access, fieldNode.name, fieldNode.desc, fieldNode.desc, fieldNode.value));
if (initInstructions != null) {
if (initInstructions.size() > 0) {
MethodNode mn = new MethodNode(Opcodes.ACC_STATIC, "<clinit>", "()V", null, null);
InsnList il = mn.instructions;
il.add(new LabelNode());
il.add(initInstructions);
il.add(new FieldInsnNode(Opcodes.PUTSTATIC, className, fieldNode.name, fieldNode.desc));
il.add(new InsnNode(Opcodes.RETURN));
newClass.methods.add(mn);
}
}
ClassWriter newCWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
newClass.accept(newCWriter);
return newCWriter.toByteArray();
}
/**
* Inserts in the helper method a list of instructions
*
* @param mNode helper method
* @param foundMethod method to be inserted.
* @return the helper method with it's new code
*/
public static MethodNode insertNewNotVoidMethod(MethodNode mNode, MethodNode foundMethod) {
mNode.instructions = foundMethod.instructions;
mNode.localVariables = foundMethod.localVariables;
mNode.maxLocals = foundMethod.maxLocals;
mNode.maxStack = foundMethod.maxStack;
mNode.instructions.resetLabels();
return mNode;
}
}