Package cn.wensiqun.asmsupport.block.control

Source Code of cn.wensiqun.asmsupport.block.control.Catch

package cn.wensiqun.asmsupport.block.control;

import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.objectweb.asm.Label;

import cn.wensiqun.asmsupport.Executeable;
import cn.wensiqun.asmsupport.Parameterized;
import cn.wensiqun.asmsupport.block.ProgramBlock;
import cn.wensiqun.asmsupport.block.method.SuperMethodBody;
import cn.wensiqun.asmsupport.clazz.AClass;
import cn.wensiqun.asmsupport.definition.variable.LocalVariable;
import cn.wensiqun.asmsupport.exception.ASMSupportException;
import cn.wensiqun.asmsupport.exception.UnreachableCode;
import cn.wensiqun.asmsupport.operators.NoneOperator;
import cn.wensiqun.asmsupport.operators.Throw;
import cn.wensiqun.asmsupport.operators.asmdirect.GOTO;
import cn.wensiqun.asmsupport.operators.asmdirect.Marker;
import cn.wensiqun.asmsupport.operators.asmdirect.NOP;
import cn.wensiqun.asmsupport.operators.asmdirect.Store;
import cn.wensiqun.asmsupport.operators.util.OperatorFactory;
import cn.wensiqun.asmsupport.utils.Stack;

/**
*
* @author 温斯群(Joe Wen)
*
*/
public abstract class Catch extends SeriesBlock {

    private static Log log = LogFactory.getLog(Catch.class);
   
    private AClass exception;
   
    private Try entityTry;
   
    private Catch nextCatch;
   
    private Finally finallyBlock;
   
    private Label catchLbl;
   
    /** Catch块结束的位置1*/
    private Label endCatchLbl1;
   
    private Label endCatchLbl2;
   
    private Label implicitCatchStartLbl;
   
    private Store implicitCatchThrowableStore;
   
    /** 该程序块中所有可执行的指令 */
    private List<Executeable> parentExes;
   
    /** 该程序块中所有可执行的指令 */
    private List<Executeable> parentPreExes;
   
    public Catch(AClass exception) {
        super();
        this.exception = exception;
        catchLbl = new Label();
        endCatchLbl1 = new Label();
        endCatchLbl2 = new Label();
        implicitCatchStartLbl = new Label();
    }
   
    void setFinallyBlock(Finally finallyBlock) {
      this.finallyBlock = finallyBlock;
  }

    public Finally getFinallyBlock() {
    return finallyBlock;
  }

  @Override
    public void executing() {
        insnHelper.mark(catchLbl);
        Stack stack = insnHelper.getMv().getStack();
        stack.push(exception.getType());
        insnHelper.nop();
       
        for(Executeable exe : getExecuteQueue()){
            if(exe.equals(implicitCatchThrowableStore)){
                stack.push(AClass.THROWABLE_ACLASS.getType());
            }
            exe.execute();
        }
       
        if(finallyBlock == null){
          //insnHelper.goTo(getTerminalEndLabelInCatch());
            insnHelper.mark(endCatchLbl2);
        }

    }

    @Override
    protected void init() {
      SuperMethodBody mb = getMethodBody();
        mb.addTryCatchInfo(entityTry.getStart(), entityTry.getEnd(), catchLbl, exception);
       
        //是最后一个Catch 并且存在Finally Block 则对try程序每个catch程序
        //添加一个隐藏的catch块(此catch程序块将catch throwable异常)
        if(finallyBlock != null){
            mb.addTryCatchInfo(entityTry.getStart(), entityTry.getEnd(), implicitCatchStartLbl, null);
         
            Catch nextCatch = entityTry.getCatchEntity();
            while(nextCatch != null){
              mb.addTryCatchInfo(nextCatch.catchLbl, endCatchLbl1, implicitCatchStartLbl, null);
              nextCatch = nextCatch.getNextCatch();
            }
        }
       
    }

    @Override
    public final void generateInsn() {
     
        Label exceptionLbl = new Label();
        LocalVariable lv = getLocalVariableModel("e", exception);
        new Store(getExecuteBlock(), lv);
       
        lv.getScopeLogicVar().setSpecifiedStartLabel(exceptionLbl);
        new Marker(getExecuteBlock(), exceptionLbl);
        catchBody(lv);
       
        new Marker(getExecuteBlock(), endCatchLbl1);
        new NOP(getExecuteBlock());
       
        Finally finallyOfCurrentTrySeries = getFinally();
       
       
        if(finallyOfCurrentTrySeries != null){
            new Marker(getExecuteBlock(), endCatchLbl2);
            try{
              //空操作 判读程序是否可以继续执行下去
              OperatorFactory.newOperator(NoneOperator.class, new Class<?>[]{ProgramBlock.class}, getExecuteBlock());
              //如果程序能够走到这里 表示之前没有return或者throw操作,则将finally内容copy至当前catch块的末尾
              finallyBlock.clonerGenerate(getExecuteBlock());
            }catch(UnreachableCode uc){
                log.info(uc.getMessage());
            }catch(RuntimeException e){
              throw e;
            }
        }
       
        try{
          //空操作 判读程序是否可以继续执行下去
            OperatorFactory.newOperator(NoneOperator.class, new Class<?>[]{ProgramBlock.class}, getExecuteBlock());
            //如果程序能够走到这里 表示之前没有return或者throw操作,跳转到finally block的起始位置
            new GOTO(this.getExecuteBlock(), getTerminalEndLabelInCatch());
        }catch(UnreachableCode uc){
            log.info("unreachable code")
        }catch(RuntimeException e){
          throw e;
        }
       
        //the finally block of current block
        Finally finallyOfCurrentCatch = finallyBlock;
        //if finally block is not null, indicate this is a last block
        if(finallyOfCurrentCatch != null){
            /*generate a hidden catch block for other uncatch exception and the block code is same to finally block */
            generateThrowableCatch();
        }
    }
   
    public abstract void catchBody(LocalVariable e);
   
    /**
     *  generate a hidden catch block for other uncatch exception and the block code is same to finally block
     * 
     */
    private void generateThrowableCatch(){
        boolean currentCheckUnrechableCode = getExecuteBlock().whetherCheckUnreachableCode();
        getExecuteBlock().setWhetherCheckUnreachableCode(false);
       
        new Marker(this.getExecuteBlock(), implicitCatchStartLbl);
       
        LocalVariable exception = getLocalAnonymousVariableModel(AClass.THROWABLE_ACLASS);
        implicitCatchThrowableStore = new Store(getExecuteBlock(), exception);
       
        finallyBlock.clonerGenerate(getExecuteBlock());
        //throwException(exception);
        OperatorFactory.newOperator(Throw.class,
                new Class<?>[]{ProgramBlock.class, Parameterized.class, boolean.class}, getExecuteBlock(), exception, true);
       
        getExecuteBlock().setWhetherCheckUnreachableCode(currentCheckUnrechableCode);
    }
   
    void setEntityTry(Try t){
        this.entityTry = t;
    }

  /**
     * 判断当前catch块或者之后的catch块是否已经catch过了异常或者catch过了其父类
     * @param exception
     * @return
     */
    public boolean checkCatch(AClass excep){
        if(excep.isChildOrEqual(exception)){
            return true;
        }else{
            if(nextCatch != null){
                return nextCatch.checkCatch(excep);
            }
        }
        return false;
    }
   
    /**
     *
     * @param ca
     * @return
     */
    public Catch catchException(Catch ca){
     
        if(this.finallyBlock != null){
            throw new ASMSupportException("cannot declare catch after finally block");
        }
       
        if(entityTry.checkCatchBlockException(ca.exception)){
            throw new ASMSupportException("the exception type " + ca.exception + " has been catch by previously catch block");
        }

        entityTry.addCatchedException(ca.getException());
        /*entityTry.getCatchedExceptions().add(ca.getException());
      entityTry.removeException(ca.getException());*/
       
        this.nextCatch = ca;
        //执行队列添加ca
        parentExes.add(ca);
        //准备队列添加ca
        parentPreExes.add(ca);
       
        //设置ca的父执行队列
        ca.setParentExes(parentExes);
        //设置ca的父准备执行队列
        ca.setParentPreExes(parentPreExes);
        //设置当前catch对应的try
        ca.setEntityTry(this.entityTry);
        ca.setPrevious(this);
       
        subBlockPrepare(ca, getOwnerBlock());
       
        return ca;
    }
   
    public Finally finallyThan(Finally fly){
        if(this.nextCatch != null){
            throw new ASMSupportException("cannot declare finally block before catch");
        }
        setFinallyBlock(fly);
        fly.setPrevious(this);

        subBlockPrepare(fly, getOwnerBlock());
       
        parentExes.add(fly);
        parentPreExes.add(fly);
        return fly;
    }
   
    @Override
  public void setReturned(boolean returned) {
    super.setReturned(returned);
   
      boolean superReturned = true;
      SeriesBlock previous = getPrevious();
      while(previous != null){
        if(!previous.isReturned()){
          superReturned = false;
          break;
        }
        previous = previous.getPrevious();
      }
      if(superReturned){
        getOwnerBlock().setReturned(returned);
      }
     
  }

  /**
     * get finally block
     * @return
     */
    public Finally getFinally(){
        if(finallyBlock != null){
            return finallyBlock;
        }else{
            if(nextCatch != null){
                return nextCatch.getFinally();
            }
        }
        return null;
    }
   
    /**
     * 设置父类
     * @param parentExes
     */
    public void setParentExes(List<Executeable> parentExes) {
        this.parentExes = parentExes;
    }

    public void setParentPreExes(List<Executeable> parentPreExes) {
        this.parentPreExes = parentPreExes;
    }
   
    /**
     * 获取try catch系列的结束的位置Label,此方法不同于getTerminalEndLabel()的地方在于:
     * 如果存在finally block的时候跳转的位置。getTerminalEndLabel跳转至finally的起始位置
     * 而catch跳转至finally的结束位置。 getTerminalEndLabel方法将会在Try中使用,
     * getTerminalEndLabelInCatch在Catch中使用的。 finally程序块无论是try结束的
     * 时候还是catch结束的时候都会执行,但如果try中没有return的时候这两个程序块如何执行
     * finally程序块的方式是不同的, try采用跳转至finally的起始位置的方式, 而catch则是将finally
     * 中的指令复制到catch内的指令的最后(如果是catch中存在return指令则会复制在catch中的
     * return指令之前)
     * @return
     */
    private Label getTerminalEndLabelInCatch(){
        if(nextCatch == null){
            if(finallyBlock != null){
                return finallyBlock.endLbl;
            }else {
                return endCatchLbl2;
            }
        }
        return nextCatch.getTerminalEndLabelInCatch();
    }
   
    Label getTerminalEndLabel(){
        if(nextCatch == null){
            if(finallyBlock != null){
                return finallyBlock.startLbl;
            }else {
                return endCatchLbl2;
            }
        }
        return nextCatch.getTerminalEndLabel();
    }

  public Catch getNextCatch() {
    return nextCatch;
  }

  public AClass getException() {
    return exception;
  }

  @Override
  public String toString() {
    return "Catch Block:" + super.toString();
  }
}
TOP

Related Classes of cn.wensiqun.asmsupport.block.control.Catch

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.