Package nginx.clojure.wave

Source Code of nginx.clojure.wave.TypeInterpreter

/*
* Copyright (c) 2008-2013, Matthias Mann
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
*     * Redistributions of source code must retain the above copyright notice,
*       this list of conditions and the following disclaimer.
*     * Redistributions in binary form must reproduce the above copyright
*       notice, this list of conditions and the following disclaimer in the
*       documentation and/or other materials provided with the distribution.
*     * Neither the name of Matthias Mann nor the names of its
*       contributors may be used to endorse or promote products derived from
*       this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package nginx.clojure.wave;

import nginx.clojure.asm.Opcodes;
import nginx.clojure.asm.Type;
import nginx.clojure.asm.tree.AbstractInsnNode;
import nginx.clojure.asm.tree.TypeInsnNode;
import nginx.clojure.asm.tree.analysis.AnalyzerException;
import nginx.clojure.asm.tree.analysis.BasicInterpreter;
import nginx.clojure.asm.tree.analysis.BasicValue;
import nginx.clojure.asm.tree.analysis.SimpleVerifier;

/**
* An extension to {@link BasicInterpreter} which collects the type of
* objects and arrays.
*
* @author Matthias Mann
*/
public class TypeInterpreter extends SimpleVerifier {

    private final MethodDatabase db;

    public TypeInterpreter(MethodDatabase db) {
        this.db = db;
    }

    @Override
    public BasicValue newValue(Type type) {
        if(type == null) {
            return BasicValue.UNINITIALIZED_VALUE;
        }
        if(type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
            return new BasicValue(type);
        }
        return super.newValue(type);
    }

    @Override
    public BasicValue newOperation(AbstractInsnNode insn) throws AnalyzerException {
        if(insn.getOpcode() == Opcodes.NEW) {
            return new NewValue(Type.getObjectType(((TypeInsnNode) insn).desc), false, insn);
        }
        return super.newOperation(insn);
    }

    @Override
    public BasicValue copyOperation(AbstractInsnNode insn, BasicValue value) throws AnalyzerException {
        if(insn.getOpcode() == Opcodes.DUP) {
            if(value instanceof NewValue) {
                NewValue newValue = (NewValue)value;
                if(!newValue.isDupped) {
                    return new NewValue(newValue.getType(), true, insn);
                }
            }
        }
        return super.copyOperation(insn, value);
    }

    @Override
    public BasicValue binaryOperation(AbstractInsnNode insn, BasicValue value1, BasicValue value2) throws AnalyzerException {
        if(insn.getOpcode() == Opcodes.AALOAD) {
            Type t1 = value1.getType();
            if(t1 == null || t1.getSort() != Type.ARRAY) {
                throw new AnalyzerException(insn, "AALOAD needs an array as first parameter");
            }
           
            Type resultType = Type.getType(t1.getDescriptor().substring(1));
            return new BasicValue(resultType);
        }
        return super.binaryOperation(insn, value1, value2);
    }

//    @Override
//    public BasicValue merge(BasicValue v, BasicValue w) {
//        if (!v.equals(w)) {
//            if(v.isReference() && w.isReference()) {
//                int dimensions = 0;
//                Type typeV = v.getType();
//                Type typeW = w.getType();
//                if(typeV.getSort() != typeW.getSort()) {
//                    db.trace("Array and none array type can't be merged: %s %s", v, w);
//                    return BasicValue.UNINITIALIZED_VALUE;
//                }
//                if(typeW.getSort() == Type.ARRAY) {
//                    dimensions = typeV.getDimensions();
//                    if(dimensions != typeW.getDimensions()) {
//                        db.trace("Arrays with different dimensions can't be merged: %s %s", v, w);
//                        return BasicValue.UNINITIALIZED_VALUE;
//                    }
//                    typeV = typeV.getElementType();
//                    typeW = typeW.getElementType();
//                    if(typeV.getSort() != Type.OBJECT || typeW.getSort() != Type.OBJECT) {
//                        db.trace("Arrays of different primitive type can't be merged: %s %s", v, w);
//                        return BasicValue.UNINITIALIZED_VALUE;
//                    }
//                }
//                String internalV = typeV.getInternalName();
//                String internalW = typeW.getInternalName();
//                if("null".equals(internalV)) {
//                    return w;
//                }
//                if("null".equals(internalW)) {
//                    return v;
//                }
//                String superClass = db.getCommonSuperClass(internalV, internalW);
//                if(superClass == null) {
//                    if(db.isException(internalW)) {
//                        db.warn("Could not determine super class for v=%s w=%s - decided to use exception %s", v, w, w);
//                        return w;
//                    }
//                    if(db.isException(internalV)) {
//                        db.warn("Could not determine super class for v=%s w=%s - decided to use exception %s", v, w, v);
//                        return v;
//                    }
//                    db.warn("Could not determine super class for v=%s w=%s - decided to use java/lang/Object", v, w);
//                    superClass = "java/lang/Object";
//                }
//                String typeDescriptor = makeTypeDescriptor(superClass, dimensions);
//                db.trace("Common super class for v=%s w=%s is %s", v, w, typeDescriptor);
//                return new BasicValue(Type.getType(typeDescriptor));
//            }
//            return BasicValue.UNINITIALIZED_VALUE;
//        }
//        return v;
//    }

    private static String makeTypeDescriptor(String className, int dimensions) {
        int len = className.length();
        char[] tmp = new char[len + 2 + dimensions];
        for(int i=0 ; i<dimensions ; i++) {
            tmp[i] = '[';
        }
        tmp[dimensions] = 'L';
        className.getChars(0, len, tmp, dimensions+1);
        tmp[dimensions+1+len] = ';';
        return new String(tmp);
    }
   
    @Override
    protected Type getSuperClass(Type t) {
      return Type.getObjectType(db.getDirectSuperClass(t.getInternalName()));
    }
   
  @Override
  protected boolean isInterface(Type t) {
    return db.isInterface(t.getInternalName());
  }
   
    @Override
    protected boolean isAssignableFrom(Type t, Type u) {

    try {
      int us = u.getSort();
      int ts = t.getSort();
      switch (ts) {
      case Type.BOOLEAN:
        return us == Type.BOOLEAN;
      case Type.BYTE:
        return us == Type.BYTE;
      case Type.CHAR:
        return us == Type.BYTE || us == Type.CHAR;
      case Type.SHORT:
        return us == Type.BYTE || us == Type.CHAR || us == Type.SHORT;
      case Type.DOUBLE:
        return us == Type.BYTE || us == Type.CHAR
            || us == Type.INT || us == Type.FLOAT || us == Type.DOUBLE;
      case Type.FLOAT:
        return us == Type.BYTE || us == Type.CHAR
            || us == Type.INT || us == Type.FLOAT;
      case Type.INT:
        return us == Type.BYTE || us == Type.CHAR
            || us == Type.INT;
      case Type.LONG:
        return us == Type.BYTE || us == Type.CHAR
        || us == Type.INT || us == Type.LONG;
      }
     
      switch (us) {
      case Type.BOOLEAN:
      case Type.BYTE:
      case Type.CHAR:
      case Type.SHORT:
      case Type.DOUBLE:
      case Type.FLOAT:
      case Type.INT:
      case Type.LONG:
        return false;
      }
     
      String tn = t.getInternalName();
     
      if (tn != null  && tn.equals("java/lang/Object")) {
        return true;
      }
     
      if (us == Type.ARRAY) {
        if ( ts == Type.ARRAY ) {
          if (t.getDimensions() == u.getDimensions() && isAssignableFrom(t.getElementType(), u.getElementType())) {
            return true;
          }else if (t.getDimensions() < u.getDimensions()) {
            Type ti = t.getElementType();
            String tin = ti.getInternalName();
            if (ti.getSort() == Type.OBJECT && ("java/lang/Object".equals(tin) || ("java/lang/Cloneable".equals(tin) || "java/io/Serializable".equals(tin) ))) {
              return true;
            }
          }
          return false;
        }else if (ts == Type.OBJECT && ("java/lang/Cloneable".equals(tn) || "java/io/Serializable".equals(tn) )){
          return true;
        }
      }
     
      // System.out.println("isAssignableFrom: " + t.getInternalName() +
      // "/" + u.getInternalName());
      boolean b = t.getInternalName().equals(u.getInternalName())
          || db.getCommonSuperClass(u.getInternalName(),
              t.getInternalName()).equals(t.getInternalName());
//       boolean ob = getClass(t).isAssignableFrom(getClass(u));
//       if (b != ob) {
//       throw new RuntimeException("isAssignableFrom : " + b + "!=" + ob
//       + ", getCommonSuperClass=" +
//       db.getCommonSuperClass(u.getInternalName(), t.getInternalName())
//       + " t :" + t.getInternalName() + ", u:" + u.getInternalName());
//       }
      return b;
    } catch (Throwable e) {
      db.error("isAssignableFrom error t=" + t + ", u=" + u, e);
      return false;
    }
    }
   
    public boolean checkAssignableFrom(Type t, Type u) {
      return isAssignableFrom(t, u);
    }
   
    public Type fetchSuperClass(Type t) {
      return getSuperClass(t);
    }
}
TOP

Related Classes of nginx.clojure.wave.TypeInterpreter

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.