Package objot.codec

Source Code of objot.codec.Clazz

//
// Copyright 2007-2010 Qianyan Cai
// Under the terms of the GNU Lesser General Public License version 2.1
//
package objot.codec;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Map;

import objot.bytecode.Bytecode;
import objot.bytecode.Instruction;
import objot.bytecode.Procedure;
import objot.util.Array2;
import objot.util.Bytes;
import objot.util.Class2;
import objot.util.Mod2;

import static objot.bytecode.Opcode.*;


public abstract class Clazz
{
  static final Field F_encs = Class2.declaredField(Clazz.class, "encs");
  protected Property[] encs;
  Map<String, Property> decs;

  static Clazz make(Codec cd, Class<?> c, Property[] es, Property[] ds,
    Map<String, Property> dNames) throws Exception
  {
    String name = c.getName().startsWith("java.") //
      ? cd.getClass().getName() + "$$" //
        + (cd.hashCode() ^ Thread.currentThread().hashCode()) + '$' //
        + c.getName().replace('.', '$') //
      : c.getName() + "$$" //
        + (cd.hashCode() ^ Thread.currentThread().hashCode()) + '$' //
        + cd.getClass().getName().replace('.', '$');
    Bytecode y = new Bytecode();
    y.head.setModifier(Mod2.PUBLIC | Mod2.FINAL | Mod2.SYNTHETIC);
    y.head.setClassCi(y.cons.addClass(y.cons.addUcs(Class2.pathName(name))));
    y.head.setSuperCi(y.cons.addClass(Clazz.class));
    y.getProcs().addProc(Procedure.addCtor0(y.cons, y.head.getSuperCi(), Mod2.PUBLIC));

    int classCi = y.cons.addClass(c);
    if (es.length > 0)
    {
      int encsCi = y.cons.addField(F_encs);
      int ableCi = y.cons.addProc(Property.M_encodable);
      int nameCi = y.cons.addField(Property.F_name);
      makeEncode(y, es, classCi, encsCi, ableCi, nameCi);
      makeEncodeRefs(y, es, classCi, encsCi, ableCi);
    }
    try
    {
      c.getDeclaredConstructor(Array2.CLASSES0);
      makeObject(y, classCi);
    }
    catch (NoSuchMethodException e)
    {
    }
    if (ds.length > 0)
    {
      makeDecode(y, ds, classCi, 0);
      makeDecode(y, ds, classCi, 1);
      makeDecode(y, ds, classCi, 2);
    }

    Clazz z = Class2.<Clazz>load(Clazz.class.getClassLoader(), name, y.normalize()) //
    .newInstance();
    z.encs = es;
    z.decs = dNames;
    return z;
  }

  protected Clazz()
  {
  }

  /**
   * Example:
   *
   * <pre>
   * {@link Property}[] es = {@link #encs};
   * A a = (A)o; // shouldn't cause ClassCastException
   * // no property 0
   * if (es[1].{@link Property#encodable}(o, ruleKey) e.{@link Encoder#refs}(a.f1);
   * // no property 1
   * if (es[3].{@link Property#encodable}(o, ruleKey)) e.{@link Encoder#refs}(a.m3());
   * ...
   * </pre>
   */
  protected void encodeRefs(Encoder e, Object o, Object ruleKey)
  {
  }

  static final Bytes NAME_encodeRefs = Bytecode.utf("encodeRefs");
  static final Bytes DESC_encodeRefs = Bytecode.utf(Class2.descript(Class2.declaredMethod1(
    Clazz.class, "encodeRefs")));

  /**
   * Example:
   *
   * <pre>
   * {@link Property}[] es = {@link #encs};
   * A a = (A)o; // shouldn't cause ClassCastException
   * if (es[0].{@link Property#encodable}(o, ruleKey))
   *   e.{@link Encoder#value(String, int)}(es[0].{@link Property#name}, a.f0);
   * if (es[1].{@link Property#encodable}(o, ruleKey))
   *   e.{@link Encoder#value(String, Object)}(es[1].{@link Property#name}, a.m1());
   * ...
   * </pre>
   */
  protected void encode(Encoder e, Object o, Object ruleKey)
  {
  }

  static final Bytes NAME_encode = Bytecode.utf("encode");
  static final Bytes DESC_encode = Bytecode.utf(Class2.descript(Class2.declaredMethod1(
    Clazz.class, "encode")));

  private static void makeEncodeRefs(Bytecode y, Property[] es, int classCi, int encsCi,
    int ableCi)
  {
    Procedure p = new Procedure(y.cons);
    p.setModifier(Mod2.PROTECTED | Mod2.FINAL);
    p.setNameCi(p.cons.addUtf(NAME_encodeRefs));
    p.setDescCi(p.cons.addUtf(DESC_encodeRefs));
    Instruction s = new Instruction(p.cons, 250);
    s.ins0(ALOAD2);
    s.insU2(CHECKCAST, classCi);
    s.insU1(ASTORE, 4); // object
    s.ins0(ALOAD0);
    s.insU2(GETFIELD, encsCi); // properties
    int refsCi = p.cons.addProc(Encoder.M_refs);
    Property e;
    for (int i = 0; i < es.length; i++)
      if ( !(e = es[i]).cla.isPrimitive() && !Number.class.isAssignableFrom(e.cla)
        && e.cla != Boolean.class)
      {
        s.ins0(DUP);
        s.insS2(SIPUSH, i);
        s.ins0(AALOAD); // property
        s.ins0(ALOAD2);
        s.ins0(ALOAD3);
        s.insU2(INVOKEVIRTUAL, ableCi);
        int if0 = s.insJump(IFIE0);
        s.ins0(ALOAD1);
        s.insU1(ALOAD, 4); // object
        if (e.field != null)
          s.insU2(GETFIELD, p.cons.addField(e.field));
        else
          s.insU2(INVOKEVIRTUAL, p.cons.addProc(e.method));
        s.insU2(INVOKEVIRTUAL, refsCi);
        s.jumpHere(if0);
      }
    s.ins0(RETURN);
    p.getCode().setIns(s, false);
    p.getCode().setLocalN(5);
    p.getCode().setStackN(4);
    y.getProcs().addProc(p);
  }

  private static final Method M_intValue = Class2.declaredMethod1(Integer.class, "intValue");
  private static final Method M_byteValue = Class2.declaredMethod1(Byte.class, "byteValue");
  private static final Method M_shortValue = Class2.declaredMethod1(Short.class,
    "shortValue");
  private static final Method M_longValue = Class2.declaredMethod1(Long.class, "longValue");
  private static final Method M_boolValue = Class2.declaredMethod1(Boolean.class,
    "booleanValue");
  private static final Method M_floatValue = Class2.declaredMethod1(Float.class,
    "floatValue");
  private static final Method M_doubleValue = Class2.declaredMethod1(Double.class,
    "doubleValue");

  private static void makeEncode(Bytecode y, Property[] es, int classCi, int encsCi,
    int ableCi, int nameCi)
  {
    Procedure p = new Procedure(y.cons);
    p.setModifier(Mod2.PROTECTED | Mod2.FINAL);
    p.setNameCi(p.cons.addUtf(NAME_encode));
    p.setDescCi(p.cons.addUtf(DESC_encode));
    Instruction s = new Instruction(y.cons, 250);
    s.ins0(ALOAD2);
    s.insU2(CHECKCAST, classCi);
    s.insU1(ASTORE, 4); // object
    s.ins0(ALOAD0);
    s.insU2(GETFIELD, encsCi); // properties
    int intCi = p.cons.addProc(Encoder.M_valueInt);
    int longCi = p.cons.addProc(Encoder.M_valueLong);
    int boolCi = p.cons.addProc(Encoder.M_valueBool);
    int floatCi = p.cons.addProc(Encoder.M_valueFloat);
    int doubleCi = p.cons.addProc(Encoder.M_valueDouble);
    int objCi = p.cons.addProc(Encoder.M_valueObject);
    int intVCi = p.cons.addProc(M_intValue);
    int byteVCi = p.cons.addProc(M_byteValue);
    int shortVCi = p.cons.addProc(M_shortValue);
    int longVCi = p.cons.addProc(M_longValue);
    int boolVCi = p.cons.addProc(M_boolValue);
    int floatVCi = p.cons.addProc(M_floatValue);
    int doubleVCi = p.cons.addProc(M_doubleValue);
    Property e;
    for (int i = 0; i < es.length; i++)
    {
      s.ins0(DUP);
      s.insS2(SIPUSH, i);
      s.ins0(AALOAD); // property
      s.ins0(DUP); // property
      s.insU1(ASTORE, 5); // property
      s.ins0(ALOAD2);
      s.ins0(ALOAD3);
      s.insU2(INVOKEVIRTUAL, ableCi);
      int if0 = s.insJump(IFIE0);
      s.ins0(ALOAD1);
      s.insU1(ALOAD, 5); // property
      s.insU2(GETFIELD, nameCi);
      s.insU1(ALOAD, 4); // object
      if ((e = es[i]).field != null)
        s.insU2(GETFIELD, p.cons.addField(e.field));
      else
        s.insU2(INVOKEVIRTUAL, p.cons.addProc(e.method));
      if (e.cla == int.class || e.cla == byte.class || e.cla == short.class)
        s.insU2(INVOKEVIRTUAL, intCi);
      else if (e.cla == long.class)
        s.insU2(INVOKEVIRTUAL, longCi);
      else if (e.cla == boolean.class)
        s.insU2(INVOKEVIRTUAL, boolCi);
      else if (e.cla == float.class)
        s.insU2(INVOKEVIRTUAL, floatCi);
      else if (e.cla == double.class)
        s.insU2(INVOKEVIRTUAL, doubleCi);
      else if (e.cla == Integer.class)
      {
        s.insU2(INVOKEVIRTUAL, intVCi);
        s.insU2(INVOKEVIRTUAL, intCi);
      }
      else if (e.cla == Byte.class)
      {
        s.insU2(INVOKEVIRTUAL, byteVCi);
        s.insU2(INVOKEVIRTUAL, intCi);
      }
      else if (e.cla == Short.class)
      {
        s.insU2(INVOKEVIRTUAL, shortVCi);
        s.insU2(INVOKEVIRTUAL, intCi);
      }
      else if (e.cla == Long.class)
      {
        s.insU2(INVOKEVIRTUAL, longVCi);
        s.insU2(INVOKEVIRTUAL, longCi);
      }
      else if (e.cla == Boolean.class)
      {
        s.insU2(INVOKEVIRTUAL, boolVCi);
        s.insU2(INVOKEVIRTUAL, boolCi);
      }
      else if (e.cla == Float.class)
      {
        s.insU2(INVOKEVIRTUAL, floatVCi);
        s.insU2(INVOKEVIRTUAL, floatCi);
      }
      else if (e.cla == Double.class)
      {
        s.insU2(INVOKEVIRTUAL, doubleVCi);
        s.insU2(INVOKEVIRTUAL, doubleCi);
      }
      else
        s.insU2(INVOKEVIRTUAL, objCi);
      s.jumpHere(if0);
    }
    s.ins0(RETURN);
    p.getCode().setIns(s, false);
    p.getCode().setLocalN(6);
    p.getCode().setStackN(5);
    y.getProcs().addProc(p);
  }

  /** Example: <code>return new A();</code> if nullary constructor found */
  protected Object object(Codec codec) throws Exception
  {
    throw new InstantiationException("no nullary constructor");
  }

  static final Bytes NAME_object = Bytecode.utf("object");
  static final Bytes DESC_object = Bytecode.utf(Class2.descript(Class2.declaredMethod1(
    Clazz.class, "object")));

  private static void makeObject(Bytecode y, int classCi)
  {
    Procedure p = new Procedure(y.cons);
    p.setModifier(Mod2.PROTECTED | Mod2.FINAL);
    p.setNameCi(p.cons.addUtf(NAME_object));
    p.setDescCi(p.cons.addUtf(DESC_object));
    Instruction s = new Instruction(p.cons, 250);
    s.insU2(NEW, classCi);
    s.ins0(DUP);
    s.insU2(INVOKESPECIAL, p.cons.addCtor0(classCi));
    s.ins0(ARETURN);
    p.getCode().setIns(s, false);
    p.getCode().setLocalN(2);
    p.getCode().setStackN(2);
    y.getProcs().addProc(p);
  }

  /**
   * Example:
   *
   * <pre>
   * A a = (A)o;
   * switch(x) {
   *   case 2: a.f2 = (Class2)v; return;
   *   case 5: a.m5((Class5)v); return;
   *   ...
   *   default: throw new ClassCastException();
   * }</pre>
   */
  protected abstract void decode(Object o, int x, Object v);

  protected abstract void decode(Object o, int x, long v);

  /** includes floats */
  protected abstract void decode(Object o, int x, double v);

  static final Bytes NAME_decode = Bytecode.utf("decode");
  static final Bytes DESC_decode = Bytecode.utf(Class2.descript( //
  Class2.declaredMethod(Clazz.class, "decode", Object.class, int.class, Object.class)));
  static final Bytes DESC_decodeL = Bytecode.utf(Class2.descript( //
  Class2.declaredMethod(Clazz.class, "decode", Object.class, int.class, long.class)));
  static final Bytes DESC_decodeD = Bytecode.utf(Class2.descript( //
  Class2.declaredMethod(Clazz.class, "decode", Object.class, int.class, double.class)));

  private static void makeDecode(Bytecode y, Property[] ds, int classCi, int type)
  {
    Procedure p = new Procedure(y.cons);
    p.setModifier(Mod2.PROTECTED | Mod2.FINAL);
    p.setNameCi(p.cons.addUtf(NAME_decode));
    p.setDescCi(p.cons.addUtf(type == 0 ? DESC_decode : type == 1 ? DESC_decodeL
      : DESC_decodeD));
    Instruction s = new Instruction(p.cons, 250);
    s.ins0(ALOAD1);
    s.insU2(CHECKCAST, classCi); // object
    s.ins0(type == 0 ? ALOAD3 : type == 1 ? LLOAD3 : DLOAD3);
    s.ins0(ILOAD2);
    long sw = s.insSwitchTable(0, ds.length - 1);
    int sw0 = s.addr; // default
    s.switchTableHere(sw, -1);
    int exCi = p.cons.addClass(ClassCastException.class);
    s.insU2(NEW, exCi);
    s.ins0(DUP);
    s.insU2(INVOKESPECIAL, p.cons.addCtor0(exCi));
    s.ins0(ATHROW);
    Property d;
    for (int i = 0; i < ds.length && (d = ds[i]) != null; i++)
      if (type == 0 ? d.cla.isPrimitive() && d.cla != boolean.class //
      : type == 1 ? d.cla != int.class && d.cla != long.class //
      : d.cla != double.class && d.cla != float.class)
        s.switchTable(sw, i, sw0);
      else
      {
        s.switchTableHere(sw, i);
        if (type == 0)
          if (d.cla == boolean.class)
            s.insUnboxNarrow(d.cla);
          else
            s.insU2(CHECKCAST, p.cons.addClass(d.cla));
        else if (type == 1 && d.cla == int.class)
          s.ins0(L2I);
        else if (type == 2 && d.cla == float.class)
          s.ins0(D2F);
        if (d.field != null)
          s.insU2(PUTFIELD, p.cons.addField(d.field));
        else
          s.insU2(INVOKEVIRTUAL, p.cons.addProc(d.method));
        s.ins0(RETURN);
      }
    p.getCode().setIns(s, false);
    p.getCode().setLocalN(5);
    p.getCode().setStackN(5);
    y.getProcs().addProc(p);
  }
}
TOP

Related Classes of objot.codec.Clazz

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.