Package net.sourceforge.javautil.bytecode.impl.asm

Source Code of net.sourceforge.javautil.bytecode.impl.asm.BytecodeWriterMethodASM

package net.sourceforge.javautil.bytecode.impl.asm;

import java.util.ArrayList;
import java.util.List;

import net.sourceforge.javautil.bytecode.BytecodeException;
import net.sourceforge.javautil.bytecode.api.IBytecodeField;
import net.sourceforge.javautil.bytecode.api.IBytecodeReferenceable;
import net.sourceforge.javautil.bytecode.api.IBytecodeResolvable;
import net.sourceforge.javautil.bytecode.api.IBytecodeWriter;
import net.sourceforge.javautil.bytecode.api.LiteralValue;
import net.sourceforge.javautil.bytecode.api.MethodDescriptor;
import net.sourceforge.javautil.bytecode.api.TypeDescriptor;
import net.sourceforge.javautil.bytecode.api.IBytecodeResolvable.ClassType;
import net.sourceforge.javautil.bytecode.api.event.BytecodeEvent;
import net.sourceforge.javautil.bytecode.api.type.AbstractType;
import net.sourceforge.javautil.bytecode.api.type.method.BytecodeBlock;
import net.sourceforge.javautil.bytecode.api.type.method.BytecodeConstructorBase;
import net.sourceforge.javautil.bytecode.api.type.method.BytecodeLocalVariableDeclaration;
import net.sourceforge.javautil.bytecode.api.type.method.IBytecodeMarker;
import net.sourceforge.javautil.bytecode.api.type.method.IBytecodeMethod;
import net.sourceforge.javautil.bytecode.api.type.method.BytecodeMethodAbstract;
import net.sourceforge.javautil.bytecode.api.type.method.BytecodeMethodConcrete;
import net.sourceforge.javautil.bytecode.api.type.method.BytecodeScope;
import net.sourceforge.javautil.bytecode.api.type.method.IBytecodeWriterMethod;
import net.sourceforge.javautil.bytecode.api.type.method.IBytecodeWriterMethod.ComparisonOperator;
import net.sourceforge.javautil.bytecode.api.type.method.IBytecodeWriterMethod.MathmaticalOperator;

import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;

/**
* A standard ASM byte code writer implementation.
*
* @author elponderador
* @author $Author$
* @version $Id$
*/
public class BytecodeWriterMethodASM implements IBytecodeWriterMethod<BytecodeContextMethodASM>, Opcodes {
 
  public void begin(BytecodeContextMethodASM context) {
    context.getTarget().visitCode();
  }

  public void end(BytecodeContextMethodASM context) {
    this.mark(context, context.getScope(0).getEnd());
   
    for (BytecodeLocalVariableDeclaration lv : context.getLocalVariables()) {
      context.getTarget().visitLocalVariable(lv.getName(), lv.getType().toDescriptorString(), null,
        ((BytecodeMarkerLabel)lv.getScope().getStart()).label,
        ((BytecodeMarkerLabel)lv.getScope().getEnd()).label,
        lv.getIndex()
      );
    }
   
    context.getTarget().visitMaxs(context.getMaxStackSize(), context.getMaxLocalVariables());
    context.getTarget().visitEnd();
  }

  public void pop(BytecodeContextMethodASM context) {
    context.getTarget().visitInsn(POP);
  }

  public void arrayLength(BytecodeContextMethodASM context) { context.getTarget().visitInsn(ARRAYLENGTH); }

  public void arrayLoad(BytecodeContextMethodASM context, TypeDescriptor type) {
    context.getTarget().visitInsn(AALOAD);
    context.popStack();
    context.popStack();
    context.push(type);
  }

  public void arrayStore(BytecodeContextMethodASM context) {
    context.getTarget().visitInsn(AASTORE);
    context.popStack();
    context.popStack();
  }

  public void box(BytecodeContextMethodASM context) {
    TypeDescriptor type = context.getStack(0);
     
    if (!type.isPrimitive()) throw new BytecodeException("Cannot box a non-primitive: " + type);
   
    //Type unboxed = getType(type);
    //context.getTarget().box(unboxed);
    context.pop(type);
    context.push(type.getBoxedType());
  }
 
  public void unbox(BytecodeContextMethodASM context) {
    TypeDescriptor type = context.getStack(0);
   
    if (type.isPrimitive()) throw new BytecodeException("Cannot unbox a primitive: " + type);
   
    //Type boxed = getType(type);
    //context.getTarget().unbox(boxed);
    context.pop(type);
    context.push(type.getUnboxedType());
  }

  public void cast(BytecodeContextMethodASM context, TypeDescriptor from, TypeDescriptor to) {
    context.pop(from);
    context.push(to);
  }

  public void catchException(BytecodeContextMethodASM context, IBytecodeMarker start, IBytecodeMarker end, TypeDescriptor exceptionType) {
    context.getTarget().visitTryCatchBlock(
      ((BytecodeMarkerLabel)start).label, ((BytecodeMarkerLabel)end).label,
      this.mark(context).label, exceptionType == null ? null : exceptionType.toDescriptorString()
    );
  }

  public void checkCast(BytecodeContextMethodASM context, TypeDescriptor type) {
    context.getTarget().visitTypeInsn(Opcodes.CHECKCAST, type.getName());
  }

  public void dup(BytecodeContextMethodASM context) {
    context.getTarget().visitInsn(DUP);
    context.push(context.getStack(0));
  }

  public void dup2(BytecodeContextMethodASM context) {
    context.getTarget().visitInsn(DUP2);
    context.push(context.getStack(0));
  }
 
  public void doMath(BytecodeContextMethodASM context, IBytecodeReferenceable value1, IBytecodeReferenceable value2, MathmaticalOperator operator) {
    value1.load(context);
    value2.load(context);
   
    Type type = getType(value1.getType());
   
    context.push(value1.getType());
    context.push(value2.getType());
   
    int opcode = 0;
    switch (operator) {
      case Multiply: opcode = type.getOpcode(IMUL); break;
      case Divide: opcode = type.getOpcode(IDIV); break;
      case Plus: opcode = type.getOpcode(IADD); break;
      case Minus: opcode = type.getOpcode(ISUB); break;
     
      default:
        throw new BytecodeException("Unsupported operator: " + operator);
    }
   
    context.popStack();
    context.popStack();
   
    context.getTarget().visitInsn(opcode);
   
    context.push(value1.getType());
  }

  public void loadNull(BytecodeContextMethodASM context) {
    context.getTarget().visitInsn(ACONST_NULL);
  }

  @Override public void loadType(BytecodeContextMethodASM context, IBytecodeResolvable type) {
    context.getTarget().visitLdcInsn(Type.getType(type.getType().toDescriptorString()));
  }

  public void loadLiteral(BytecodeContextMethodASM context, LiteralValue literal) {
    Type type = getType(literal.getType());
    if (literal.getValue() instanceof Number || literal.getValue() instanceof Character) {
      Number value = literal.getValue() instanceof Character ? (int) ((Character)literal.getValue()).charValue() : (Number) literal.getValue();
      if (value instanceof Double || value instanceof Float || value.longValue() > Short.MAX_VALUE) {
        context.getTarget().visitLdcInsn(value);
      } else {
        int i = value.intValue();
        if (i <= 5) context.getTarget().visitInsn(ICONST_0 + i);
        else if (i <= Byte.MAX_VALUE) context.getTarget().visitIntInsn(BIPUSH, i);
        else context.getTarget().visitIntInsn(SIPUSH, i);
      }
    } else if (type == Type.BOOLEAN_TYPE) {
      boolean value = (Boolean) literal.getValue();
      context.getTarget().visitInsn(value ? ICONST_1 : ICONST_0);
    } else {
      context.getTarget().visitLdcInsn(literal.getValue());
    }
   
    context.push(literal.getType());
  }

  public void storeLocal (BytecodeContextMethodASM context, int idx) {
    Type type = getType(context.getLocalVariable(idx).getType());
    context.getTarget().visitVarInsn(type.getOpcode(ISTORE), idx);
    context.popStack();
  }
 
  public void loadLocal (BytecodeContextMethodASM context, int idx) {
    TypeDescriptor ts = context.getLocalVariable(idx).getType();
    Type type = getType(ts);
    context.getTarget().visitVarInsn(type.getOpcode(ILOAD), idx);
    context.push(ts);
  }
 
  public void loadField(BytecodeContextMethodASM context, IBytecodeResolvable type, String name) {
    IBytecodeField field = type.getField(context.getResolutionPool(), name);
    if (field == null) throw new BytecodeException("No such field " + name + " for " + type.getType().getClassName());
   
    context.getTarget().visitFieldInsn(GETFIELD, type.getType().getName(), name, field.getType().toDescriptorString());
    context.popStack();
    context.push(field.getType());
  }

  public void loadStaticField(BytecodeContextMethodASM context, IBytecodeResolvable type, String name) {
    IBytecodeField field = type.getField(context.getResolutionPool(), name);
    if (field == null) throw new BytecodeException("No such field " + name + " for " + type.getType().getClassName());
   
    context.getTarget().visitFieldInsn(GETSTATIC, type.getType().getName(), name, field.getType().toDescriptorString());
    context.push(field.getType());
  }

  public void storeField(BytecodeContextMethodASM context, IBytecodeResolvable type, String name) {
    IBytecodeField field = type.getField(context.getResolutionPool(), name);
    if (field == null) throw new BytecodeException("No such field " + name + " for " + type.getType().getClassName());
   
    context.getTarget().visitFieldInsn(PUTFIELD, type.getType().getName(), name, field.getType().toDescriptorString());
    context.popStack();
    context.popStack();
  }

  public void storeStaticField(BytecodeContextMethodASM context, IBytecodeResolvable type, String name) {
    IBytecodeField field = type.getField(context.getResolutionPool(), name);
    if (field == null) throw new BytecodeException("No such field " + name + " for " + type.getType().getClassName());
   
    context.getTarget().visitFieldInsn(PUTSTATIC, type.getType().getName(), name, field.getType().toDescriptorString());
    context.popStack();
  }

  public void newArray(BytecodeContextMethodASM context, TypeDescriptor type, IBytecodeReferenceable... indices) {
    for (IBytecodeReferenceable length : indices) length.load(context);
    if (indices.length == 1) {
      context.getTarget().visitTypeInsn(ANEWARRAY, type.getName());
      context.push(type.getArrayType(1));
    } else {
      TypeDescriptor atype = type.getArrayType(indices.length);
      context.getTarget().visitMultiANewArrayInsn(atype.getName(), indices.length);
      context.push(atype);
    }
  }

  public void newInstance (BytecodeContextMethodASM context, TypeDescriptor typeDescriptor) {
    context.getTarget().visitTypeInsn(NEW, typeDescriptor.getName());
    context.push(typeDescriptor);
  }
 
  public void throwException(BytecodeContextMethodASM context) {
    context.getTarget().visitInsn(ATHROW);
  }

  public void invoke(BytecodeContextMethodASM context, IBytecodeResolvable type, IBytecodeMethod method) {
    String desc = method.getDescriptor().toDescriptorString();
   
    int opcode = Opcodes.INVOKEVIRTUAL;
   
    if ("<init>".equals(method.getName())) opcode = Opcodes.INVOKESPECIAL;
    else if (method.getAccess().isStatic()) opcode = Opcodes.INVOKESTATIC;
    else if (method.getDeclaringType().compareTo(type) != 0) opcode = Opcodes.INVOKESPECIAL;
    else if (method.getDeclaringType().getClassType() == ClassType.Interface) opcode = Opcodes.INVOKEINTERFACE;
   
    context.getTarget().visitMethodInsn(opcode, method.getDeclaringType().getType().getName(), method.getName(), desc);
   
    if (opcode != Opcodes.INVOKESTATIC) context.popStack();
    for (int i=0; i<method.getDescriptor().getParameters().length; i++) context.popStack();
   
    TypeDescriptor rt = method.getDescriptor().getReturnType();
    if (rt != null && rt != TypeDescriptor.VOID) context.push(rt);
  }
 
  public void returnValue(BytecodeContextMethodASM context, TypeDescriptor td) {
    if (td == null) {
      this.loadNull(context);
      context.getTarget().visitInsn(ARETURN);
    } else {
      Type type = getType(td);
      context.getTarget().visitInsn(type.getOpcode(IRETURN));
    }
  }

  public void returnVoid(BytecodeContextMethodASM context) {
    context.getTarget().visitInsn(RETURN);
  }

  public void jump(BytecodeContextMethodASM context, IBytecodeMarker marker) {
    context.getTarget().visitJumpInsn(GOTO, ((BytecodeMarkerLabel)marker).label);
  }

  public void jumpIf(BytecodeContextMethodASM context, IBytecodeReferenceable arg1, IBytecodeReferenceable arg2, ComparisonOperator operator, boolean negate, IBytecodeMarker marker) {
    arg1.load(context);
    arg2.load(context);
   
    context.getTarget().visitJumpInsn(this.getIfOpcode(arg1.getType(), arg2.getType(), operator, negate), ((BytecodeMarkerLabel)marker).label);
  }

  public void jumpIfException(BytecodeContextMethodASM context, IBytecodeMarker codeStart, IBytecodeMarker codeEnd, IBytecodeMarker handler, TypeDescriptor type) {
    context.getTarget().visitTryCatchBlock(getLabel(codeStart), getLabel(codeEnd), getLabel(handler), type.getName());
  }

  public void jumpFinally(BytecodeContextMethodASM context, IBytecodeMarker codeStart, IBytecodeMarker finallyMarker) {
    context.getTarget().visitTryCatchBlock(getLabel(codeStart), getLabel(finallyMarker), getLabel(finallyMarker), null);
  }

  public BytecodeMarkerLabel createMarker(BytecodeContextMethodASM context) { return new BytecodeMarkerLabel(); }

  public BytecodeMarkerLabel mark(BytecodeContextMethodASM context) {
    BytecodeMarkerLabel label = new BytecodeMarkerLabel();
    label.write(context);
    return label;
  }

  public void mark(BytecodeContextMethodASM context, IBytecodeMarker marker) { marker.write(context); }

  public void handle(BytecodeEvent evt) {
   
  }
 
  /**
   * @param marker The original marker
   * @return The ASM marker
   */
  protected Label getLabel (IBytecodeMarker marker) {
    return ((BytecodeMarkerLabel)marker).label;
  }
 
  /**
   * @param td The type descriptor
   * @return The corresponding type
   */
  protected Type getType (TypeDescriptor td) { return Type.getType(td.toDescriptorString()); }
 
  /**
   * @param arg1 The first argument
   * @param arg2 The second argument
   * @param comparator The comparator to use
   * @param negate True if the comparison is negated
   * @return The corresponding opcode to use
   */
  protected int getIfOpcode (TypeDescriptor arg1, TypeDescriptor arg2, ComparisonOperator comparator, boolean negate) {
    if (arg1 == TypeDescriptor.INTEGER && arg2 == TypeDescriptor.INTEGER) {
      switch (comparator) {
        case Equals: return negate ? IF_ICMPNE : IF_ICMPEQ;
        case GreaterThan: return negate ? IF_ICMPLE : IF_ICMPGT;
        case LesserThan: return negate ? IF_ICMPGE : IF_ICMPLT;
        case GreaterEqual: return negate ? IF_ICMPLT : IF_ICMPGE;
        case LesserEqual: return negate ? IF_ICMPGT : IF_ICMPLE;
      }
    } else if (arg2 == null) {
      return negate ? IFNONNULL : IFNULL;
    } else if (arg1.isPrimitive() && arg2.isPrimitive()) {
      switch (comparator) {
        case Equals: return negate ? IFNE : IFEQ;
        case GreaterThan: return negate ? IFLE : IFGT;
        case LesserThan: return negate ? IFGE : IFLT;
        case GreaterEqual: return negate ? IFLT : IFGE;
        case LesserEqual: return negate ? IFGT : IFLE;
      }
    } else {
      switch (comparator) {
        case Equals: return negate ? IF_ACMPNE : IF_ACMPEQ;
      }
    }

    throw new BytecodeException("Unsupported operator type for comparison arguments: " + comparator);
  }

}
TOP

Related Classes of net.sourceforge.javautil.bytecode.impl.asm.BytecodeWriterMethodASM

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.