Save This Page
Home » cglib-src-2.2 » net.sf.cglib.core » [javadoc | source]
    1   /*
    2    * Copyright 2003,2004 The Apache Software Foundation
    3    *
    4    *  Licensed under the Apache License, Version 2.0 (the "License");
    5    * you may not use this file except in compliance with the License.
    6    * You may obtain a copy of the License at
    7    *
    8    *      http://www.apache.org/licenses/LICENSE-2.0
    9    *
   10    *  Unless required by applicable law or agreed to in writing, software
   11    * distributed under the License is distributed on an "AS IS" BASIS,
   12    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   13    * See the License for the specific language governing permissions and
   14    * limitations under the License.
   15    */
   16   package net.sf.cglib.core;
   17   
   18   import java.io;
   19   import java.util;
   20   import org.objectweb.asm;
   21   
   22   /**
   23    * @author Juozas Baliuka, Chris Nokleberg
   24    */
   25   public class CodeEmitter extends LocalVariablesSorter {
   26       private static final Signature BOOLEAN_VALUE =
   27         TypeUtils.parseSignature("boolean booleanValue()");
   28       private static final Signature CHAR_VALUE =
   29         TypeUtils.parseSignature("char charValue()");
   30       private static final Signature LONG_VALUE =
   31         TypeUtils.parseSignature("long longValue()");
   32       private static final Signature DOUBLE_VALUE =
   33         TypeUtils.parseSignature("double doubleValue()");
   34       private static final Signature FLOAT_VALUE =
   35         TypeUtils.parseSignature("float floatValue()");
   36       private static final Signature INT_VALUE =
   37         TypeUtils.parseSignature("int intValue()");
   38       private static final Signature CSTRUCT_NULL =
   39         TypeUtils.parseConstructor("");
   40       private static final Signature CSTRUCT_STRING =
   41         TypeUtils.parseConstructor("String");
   42   
   43       public static final int ADD = Constants.IADD;
   44       public static final int MUL = Constants.IMUL;
   45       public static final int XOR = Constants.IXOR;
   46       public static final int USHR = Constants.IUSHR;
   47       public static final int SUB = Constants.ISUB;
   48       public static final int DIV = Constants.IDIV;
   49       public static final int NEG = Constants.INEG;
   50       public static final int REM = Constants.IREM;
   51       public static final int AND = Constants.IAND;
   52       public static final int OR = Constants.IOR;
   53   
   54       public static final int GT = Constants.IFGT;
   55       public static final int LT = Constants.IFLT;
   56       public static final int GE = Constants.IFGE;
   57       public static final int LE = Constants.IFLE;
   58       public static final int NE = Constants.IFNE;
   59       public static final int EQ = Constants.IFEQ;
   60   
   61       private ClassEmitter ce;
   62       private State state;
   63   
   64       private static class State
   65       extends MethodInfo
   66       {
   67           ClassInfo classInfo;
   68           int access;
   69           Signature sig;
   70           Type[] argumentTypes;
   71           int localOffset;
   72           Type[] exceptionTypes;
   73   
   74           State(ClassInfo classInfo, int access, Signature sig, Type[] exceptionTypes) {
   75               this.classInfo = classInfo;
   76               this.access = access;
   77               this.sig = sig;
   78               this.exceptionTypes = exceptionTypes;
   79               localOffset = TypeUtils.isStatic(access) ? 0 : 1;
   80               argumentTypes = sig.getArgumentTypes();
   81           }
   82   
   83           public ClassInfo getClassInfo() {
   84               return classInfo;
   85           }
   86   
   87           public int getModifiers() {
   88               return access;
   89           }
   90   
   91           public Signature getSignature() {
   92               return sig;
   93           }
   94   
   95           public Type[] getExceptionTypes() {
   96               return exceptionTypes;
   97           }
   98   
   99           public Attribute getAttribute() {
  100               // TODO
  101               return null;
  102           }
  103       }
  104   
  105       CodeEmitter(ClassEmitter ce, MethodVisitor mv, int access, Signature sig, Type[] exceptionTypes) {
  106           super(access, sig.getDescriptor(), mv);
  107           this.ce = ce;
  108           state = new State(ce.getClassInfo(), access, sig, exceptionTypes);
  109       }
  110   
  111       public CodeEmitter(CodeEmitter wrap) {
  112           super(wrap);
  113           this.ce = wrap.ce;
  114           this.state = wrap.state;
  115       }
  116   
  117       public boolean isStaticHook() {
  118           return false;
  119       }
  120   
  121       public Signature getSignature() {
  122           return state.sig;
  123       }
  124   
  125       public Type getReturnType() {
  126           return state.sig.getReturnType();
  127       }
  128   
  129       public MethodInfo getMethodInfo() {
  130           return state;
  131       }
  132   
  133       public ClassEmitter getClassEmitter() {
  134           return ce;
  135       }
  136   
  137       public void end_method() {
  138           visitMaxs(0, 0);
  139       }
  140   
  141       public Block begin_block() {
  142           return new Block(this);
  143       }
  144   
  145       public void catch_exception(Block block, Type exception) {
  146           if (block.getEnd() == null) {
  147               throw new IllegalStateException("end of block is unset");
  148           }
  149           mv.visitTryCatchBlock(block.getStart(),
  150                                 block.getEnd(),
  151                                 mark(),
  152                                 exception.getInternalName());
  153       }
  154   
  155       public void goTo(Label label) { mv.visitJumpInsn(Constants.GOTO, label); }
  156       public void ifnull(Label label) { mv.visitJumpInsn(Constants.IFNULL, label); }
  157       public void ifnonnull(Label label) { mv.visitJumpInsn(Constants.IFNONNULL, label); }
  158   
  159       public void if_jump(int mode, Label label) {
  160           mv.visitJumpInsn(mode, label);
  161       }
  162   
  163       public void if_icmp(int mode, Label label) {
  164           if_cmp(Type.INT_TYPE, mode, label);
  165       }
  166   
  167       public void if_cmp(Type type, int mode, Label label) {
  168           int intOp = -1;
  169           int jumpmode = mode;
  170           switch (mode) {
  171           case GE: jumpmode = LT; break;
  172           case LE: jumpmode = GT; break;
  173           }
  174           switch (type.getSort()) {
  175           case Type.LONG:
  176               mv.visitInsn(Constants.LCMP);
  177               break;
  178           case Type.DOUBLE:
  179               mv.visitInsn(Constants.DCMPG);
  180               break;
  181           case Type.FLOAT:
  182               mv.visitInsn(Constants.FCMPG);
  183               break;
  184           case Type.ARRAY:
  185           case Type.OBJECT:
  186               switch (mode) {
  187               case EQ:
  188                   mv.visitJumpInsn(Constants.IF_ACMPEQ, label);
  189                   return;
  190               case NE:
  191                   mv.visitJumpInsn(Constants.IF_ACMPNE, label);
  192                   return;
  193               }
  194               throw new IllegalArgumentException("Bad comparison for type " + type);
  195           default:
  196               switch (mode) {
  197               case EQ: intOp = Constants.IF_ICMPEQ; break;
  198               case NE: intOp = Constants.IF_ICMPNE; break;
  199               case GE: swap(); /* fall through */
  200               case LT: intOp = Constants.IF_ICMPLT; break;
  201               case LE: swap(); /* fall through */
  202               case GT: intOp = Constants.IF_ICMPGT; break;
  203               }
  204               mv.visitJumpInsn(intOp, label);
  205               return;
  206           }
  207           if_jump(jumpmode, label);
  208       }
  209   
  210       public void pop() { mv.visitInsn(Constants.POP); }
  211       public void pop2() { mv.visitInsn(Constants.POP2); }
  212       public void dup() { mv.visitInsn(Constants.DUP); }
  213       public void dup2() { mv.visitInsn(Constants.DUP2); }
  214       public void dup_x1() { mv.visitInsn(Constants.DUP_X1); }
  215       public void dup_x2() { mv.visitInsn(Constants.DUP_X2); }
  216       public void dup2_x1() { mv.visitInsn(Constants.DUP2_X1); }
  217       public void dup2_x2() { mv.visitInsn(Constants.DUP2_X2); }
  218       public void swap() { mv.visitInsn(Constants.SWAP); }
  219       public void aconst_null() { mv.visitInsn(Constants.ACONST_NULL); }
  220   
  221       public void swap(Type prev, Type type) {
  222           if (type.getSize() == 1) {
  223               if (prev.getSize() == 1) {
  224                   swap(); // same as dup_x1(), pop();
  225               } else {
  226                   dup_x2();
  227                   pop();
  228               }
  229           } else {
  230               if (prev.getSize() == 1) {
  231                   dup2_x1();
  232                   pop2();
  233               } else {
  234                   dup2_x2();
  235                   pop2();
  236               }
  237           }
  238       }
  239   
  240       public void monitorenter() { mv.visitInsn(Constants.MONITORENTER); }
  241       public void monitorexit() { mv.visitInsn(Constants.MONITOREXIT); }
  242   
  243       public void math(int op, Type type) { mv.visitInsn(type.getOpcode(op)); }
  244   
  245       public void array_load(Type type) { mv.visitInsn(type.getOpcode(Constants.IALOAD)); }
  246       public void array_store(Type type) { mv.visitInsn(type.getOpcode(Constants.IASTORE)); }
  247   
  248       /**
  249        * Casts from one primitive numeric type to another
  250        */
  251       public void cast_numeric(Type from, Type to) {
  252           if (from != to) {
  253               if (from == Type.DOUBLE_TYPE) {
  254                   if (to == Type.FLOAT_TYPE) {
  255                       mv.visitInsn(Constants.D2F);
  256                   } else if (to == Type.LONG_TYPE) {
  257                       mv.visitInsn(Constants.D2L);
  258                   } else {
  259                       mv.visitInsn(Constants.D2I);
  260                       cast_numeric(Type.INT_TYPE, to);
  261                   }
  262               } else if (from == Type.FLOAT_TYPE) {
  263                   if (to == Type.DOUBLE_TYPE) {
  264                       mv.visitInsn(Constants.F2D);
  265                   } else if (to == Type.LONG_TYPE) {
  266                       mv.visitInsn(Constants.F2L);
  267                   } else {
  268                       mv.visitInsn(Constants.F2I);
  269                       cast_numeric(Type.INT_TYPE, to);
  270                   }
  271               } else if (from == Type.LONG_TYPE) {
  272                   if (to == Type.DOUBLE_TYPE) {
  273                       mv.visitInsn(Constants.L2D);
  274                   } else if (to == Type.FLOAT_TYPE) {
  275                       mv.visitInsn(Constants.L2F);
  276                   } else {
  277                       mv.visitInsn(Constants.L2I);
  278                       cast_numeric(Type.INT_TYPE, to);
  279                   }
  280               } else {
  281                   if (to == Type.BYTE_TYPE) {
  282                       mv.visitInsn(Constants.I2B);
  283                   } else if (to == Type.CHAR_TYPE) {
  284                       mv.visitInsn(Constants.I2C);
  285                   } else if (to == Type.DOUBLE_TYPE) {
  286                       mv.visitInsn(Constants.I2D);
  287                   } else if (to == Type.FLOAT_TYPE) {
  288                       mv.visitInsn(Constants.I2F);
  289                   } else if (to == Type.LONG_TYPE) {
  290                       mv.visitInsn(Constants.I2L);
  291                   } else if (to == Type.SHORT_TYPE) {
  292                       mv.visitInsn(Constants.I2S);
  293                   }
  294               }
  295           }
  296       }
  297   
  298       public void push(int i) {
  299           if (i < -1) {
  300               mv.visitLdcInsn(new Integer(i));
  301           } else if (i <= 5) {
  302               mv.visitInsn(TypeUtils.ICONST(i));
  303           } else if (i <= Byte.MAX_VALUE) {
  304               mv.visitIntInsn(Constants.BIPUSH, i);
  305           } else if (i <= Short.MAX_VALUE) {
  306               mv.visitIntInsn(Constants.SIPUSH, i);
  307           } else {
  308               mv.visitLdcInsn(new Integer(i));
  309           }
  310       }
  311       
  312       public void push(long value) {
  313           if (value == 0L || value == 1L) {
  314               mv.visitInsn(TypeUtils.LCONST(value));
  315           } else {
  316               mv.visitLdcInsn(new Long(value));
  317           }
  318       }
  319       
  320       public void push(float value) {
  321           if (value == 0f || value == 1f || value == 2f) {
  322               mv.visitInsn(TypeUtils.FCONST(value));
  323           } else {
  324               mv.visitLdcInsn(new Float(value));
  325           }
  326       }
  327       public void push(double value) {
  328           if (value == 0d || value == 1d) {
  329               mv.visitInsn(TypeUtils.DCONST(value));
  330           } else {
  331               mv.visitLdcInsn(new Double(value));
  332           }
  333       }
  334       
  335       public void push(String value) {
  336           mv.visitLdcInsn(value);
  337       }
  338   
  339       public void newarray() {
  340           newarray(Constants.TYPE_OBJECT);
  341       }
  342   
  343       public void newarray(Type type) {
  344           if (TypeUtils.isPrimitive(type)) {
  345               mv.visitIntInsn(Constants.NEWARRAY, TypeUtils.NEWARRAY(type));
  346           } else {
  347               emit_type(Constants.ANEWARRAY, type);
  348           }
  349       }
  350       
  351       public void arraylength() {
  352           mv.visitInsn(Constants.ARRAYLENGTH);
  353       }
  354       
  355       public void load_this() {
  356           if (TypeUtils.isStatic(state.access)) {
  357               throw new IllegalStateException("no 'this' pointer within static method");
  358           }
  359           mv.visitVarInsn(Constants.ALOAD, 0);
  360       }
  361       
  362       /**
  363        * Pushes all of the arguments of the current method onto the stack.
  364        */
  365       public void load_args() {
  366           load_args(0, state.argumentTypes.length);
  367       }
  368   
  369       /**
  370        * Pushes the specified argument of the current method onto the stack.
  371        * @param index the zero-based index into the argument list
  372        */
  373       public void load_arg(int index) {
  374           load_local(state.argumentTypes[index],
  375                      state.localOffset + skipArgs(index));
  376       }
  377   
  378       // zero-based (see load_this)
  379       public void load_args(int fromArg, int count) {
  380           int pos = state.localOffset + skipArgs(fromArg);
  381           for (int i = 0; i < count; i++) {
  382               Type t = state.argumentTypes[fromArg + i];
  383               load_local(t, pos);
  384               pos += t.getSize();
  385           }
  386       }
  387       
  388       private int skipArgs(int numArgs) {
  389           int amount = 0;
  390           for (int i = 0; i < numArgs; i++) {
  391               amount += state.argumentTypes[i].getSize();
  392           }
  393           return amount;
  394       }
  395   
  396       private void load_local(Type t, int pos) {
  397           // TODO: make t == null ok?
  398           mv.visitVarInsn(t.getOpcode(Constants.ILOAD), pos);
  399       }
  400   
  401       private void store_local(Type t, int pos) {
  402           // TODO: make t == null ok?
  403           mv.visitVarInsn(t.getOpcode(Constants.ISTORE), pos);
  404       }
  405       
  406       public void iinc(Local local, int amount) {
  407           mv.visitIincInsn(local.getIndex(), amount);
  408       }
  409       
  410       public void store_local(Local local) {
  411           store_local(local.getType(), local.getIndex());
  412       }
  413       
  414       public void load_local(Local local) {
  415           load_local(local.getType(), local.getIndex());
  416       }
  417   
  418       public void return_value() {
  419           mv.visitInsn(state.sig.getReturnType().getOpcode(Constants.IRETURN));
  420       }
  421   
  422       public void getfield(String name) {
  423           ClassEmitter.FieldInfo info = ce.getFieldInfo(name);
  424           int opcode = TypeUtils.isStatic(info.access) ? Constants.GETSTATIC : Constants.GETFIELD;
  425           emit_field(opcode, ce.getClassType(), name, info.type);
  426       }
  427       
  428       public void putfield(String name) {
  429           ClassEmitter.FieldInfo info = ce.getFieldInfo(name);
  430           int opcode = TypeUtils.isStatic(info.access) ? Constants.PUTSTATIC : Constants.PUTFIELD;
  431           emit_field(opcode, ce.getClassType(), name, info.type);
  432       }
  433   
  434       public void super_getfield(String name, Type type) {
  435           emit_field(Constants.GETFIELD, ce.getSuperType(), name, type);
  436       }
  437       
  438       public void super_putfield(String name, Type type) {
  439           emit_field(Constants.PUTFIELD, ce.getSuperType(), name, type);
  440       }
  441   
  442       public void super_getstatic(String name, Type type) {
  443           emit_field(Constants.GETSTATIC, ce.getSuperType(), name, type);
  444       }
  445       
  446       public void super_putstatic(String name, Type type) {
  447           emit_field(Constants.PUTSTATIC, ce.getSuperType(), name, type);
  448       }
  449   
  450       public void getfield(Type owner, String name, Type type) {
  451           emit_field(Constants.GETFIELD, owner, name, type);
  452       }
  453       
  454       public void putfield(Type owner, String name, Type type) {
  455           emit_field(Constants.PUTFIELD, owner, name, type);
  456       }
  457   
  458       public void getstatic(Type owner, String name, Type type) {
  459           emit_field(Constants.GETSTATIC, owner, name, type);
  460       }
  461       
  462       public void putstatic(Type owner, String name, Type type) {
  463           emit_field(Constants.PUTSTATIC, owner, name, type);
  464       }
  465   
  466       // package-protected for EmitUtils, try to fix
  467       void emit_field(int opcode, Type ctype, String name, Type ftype) {
  468           mv.visitFieldInsn(opcode,
  469                             ctype.getInternalName(),
  470                             name,
  471                             ftype.getDescriptor());
  472       }
  473   
  474       public void super_invoke() {
  475           super_invoke(state.sig);
  476       }
  477   
  478       public void super_invoke(Signature sig) {
  479           emit_invoke(Constants.INVOKESPECIAL, ce.getSuperType(), sig);
  480       }
  481   
  482       public void invoke_constructor(Type type) {
  483           invoke_constructor(type, CSTRUCT_NULL);
  484       }
  485   
  486       public void super_invoke_constructor() {
  487           invoke_constructor(ce.getSuperType());
  488       }
  489       
  490       public void invoke_constructor_this() {
  491           invoke_constructor(ce.getClassType());
  492       }
  493   
  494       private void emit_invoke(int opcode, Type type, Signature sig) {
  495           if (sig.getName().equals(Constants.CONSTRUCTOR_NAME) &&
  496               ((opcode == Constants.INVOKEVIRTUAL) ||
  497                (opcode == Constants.INVOKESTATIC))) {
  498               // TODO: error
  499           }
  500           mv.visitMethodInsn(opcode,
  501                              type.getInternalName(),
  502                              sig.getName(),
  503                              sig.getDescriptor());
  504       }
  505       
  506       public void invoke_interface(Type owner, Signature sig) {
  507           emit_invoke(Constants.INVOKEINTERFACE, owner, sig);
  508       }
  509   
  510       public void invoke_virtual(Type owner, Signature sig) {
  511           emit_invoke(Constants.INVOKEVIRTUAL, owner, sig);
  512       }
  513   
  514       public void invoke_static(Type owner, Signature sig) {
  515           emit_invoke(Constants.INVOKESTATIC, owner, sig);
  516       }
  517   
  518       public void invoke_virtual_this(Signature sig) {
  519           invoke_virtual(ce.getClassType(), sig);
  520       }
  521   
  522       public void invoke_static_this(Signature sig) {
  523           invoke_static(ce.getClassType(), sig);
  524       }
  525   
  526       public void invoke_constructor(Type type, Signature sig) {
  527           emit_invoke(Constants.INVOKESPECIAL, type, sig);
  528       }
  529   
  530       public void invoke_constructor_this(Signature sig) {
  531           invoke_constructor(ce.getClassType(), sig);
  532       }
  533   
  534       public void super_invoke_constructor(Signature sig) {
  535           invoke_constructor(ce.getSuperType(), sig);
  536       }
  537       
  538       public void new_instance_this() {
  539           new_instance(ce.getClassType());
  540       }
  541   
  542       public void new_instance(Type type) {
  543           emit_type(Constants.NEW, type);
  544       }
  545   
  546       private void emit_type(int opcode, Type type) {
  547           String desc;
  548           if (TypeUtils.isArray(type)) {
  549               desc = type.getDescriptor();
  550           } else {
  551               desc = type.getInternalName();
  552           }
  553           mv.visitTypeInsn(opcode, desc);
  554       }
  555   
  556       public void aaload(int index) {
  557           push(index);
  558           aaload();
  559       }
  560   
  561       public void aaload() { mv.visitInsn(Constants.AALOAD); }
  562       public void aastore() { mv.visitInsn(Constants.AASTORE); }
  563       public void athrow() { mv.visitInsn(Constants.ATHROW); }
  564   
  565       public Label make_label() {
  566           return new Label();
  567       }
  568       
  569       public Local make_local() {
  570           return make_local(Constants.TYPE_OBJECT);
  571       }
  572       
  573       public Local make_local(Type type) {
  574           return new Local(newLocal(type.getSize()), type);
  575       }
  576   
  577       public void checkcast_this() {
  578           checkcast(ce.getClassType());
  579       }
  580       
  581       public void checkcast(Type type) {
  582           if (!type.equals(Constants.TYPE_OBJECT)) {
  583               emit_type(Constants.CHECKCAST, type);
  584           }
  585       }
  586   
  587       public void instance_of(Type type) {
  588           emit_type(Constants.INSTANCEOF, type);
  589       }
  590       
  591       public void instance_of_this() {
  592           instance_of(ce.getClassType());
  593       }
  594   
  595       public void process_switch(int[] keys, ProcessSwitchCallback callback) {
  596           float density;
  597           if (keys.length == 0) {
  598               density = 0;
  599           } else {
  600               density = (float)keys.length / (keys[keys.length - 1] - keys[0] + 1);
  601           }
  602           process_switch(keys, callback, density >= 0.5f);
  603       }
  604   
  605       public void process_switch(int[] keys, ProcessSwitchCallback callback, boolean useTable) {
  606           if (!isSorted(keys))
  607               throw new IllegalArgumentException("keys to switch must be sorted ascending");
  608           Label def = make_label();
  609           Label end = make_label();
  610   
  611           try {
  612               if (keys.length > 0) {
  613                   int len = keys.length;
  614                   int min = keys[0];
  615                   int max = keys[len - 1];
  616                   int range = max - min + 1;
  617   
  618                   if (useTable) {
  619                       Label[] labels = new Label[range];
  620                       Arrays.fill(labels, def);
  621                       for (int i = 0; i < len; i++) {
  622                           labels[keys[i] - min] = make_label();
  623                       }
  624                       mv.visitTableSwitchInsn(min, max, def, labels);
  625                       for (int i = 0; i < range; i++) {
  626                           Label label = labels[i];
  627                           if (label != def) {
  628                               mark(label);
  629                               callback.processCase(i + min, end);
  630                           }
  631                       }
  632                   } else {
  633                       Label[] labels = new Label[len];
  634                       for (int i = 0; i < len; i++) {
  635                           labels[i] = make_label();
  636                       }
  637                       mv.visitLookupSwitchInsn(def, keys, labels);
  638                       for (int i = 0; i < len; i++) {
  639                           mark(labels[i]);
  640                           callback.processCase(keys[i], end);
  641                       }
  642                   }
  643               }
  644   
  645               mark(def);
  646               callback.processDefault();
  647               mark(end);
  648   
  649           } catch (RuntimeException e) {
  650               throw e;
  651           } catch (Error e) {
  652               throw e;
  653           } catch (Exception e) {
  654               throw new CodeGenerationException(e);
  655           }
  656       }
  657   
  658       private static boolean isSorted(int[] keys) {
  659           for (int i = 1; i < keys.length; i++) {
  660               if (keys[i] < keys[i - 1])
  661                   return false;
  662           }
  663           return true;
  664       }
  665   
  666       public void mark(Label label) {
  667           mv.visitLabel(label);
  668       }
  669   
  670       Label mark() {
  671           Label label = make_label();
  672           mv.visitLabel(label);
  673           return label;
  674       }
  675   
  676       public void push(boolean value) {
  677           push(value ? 1 : 0);
  678       }
  679   
  680       /**
  681        * Toggles the integer on the top of the stack from 1 to 0 or vice versa
  682        */
  683       public void not() {
  684           push(1);
  685           math(XOR, Type.INT_TYPE);
  686       }
  687   
  688       public void throw_exception(Type type, String msg) {
  689           new_instance(type);
  690           dup();
  691           push(msg);
  692           invoke_constructor(type, CSTRUCT_STRING);
  693           athrow();
  694       }
  695   
  696       /**
  697        * If the argument is a primitive class, replaces the primitive value
  698        * on the top of the stack with the wrapped (Object) equivalent. For
  699        * example, char -> Character.
  700        * If the class is Void, a null is pushed onto the stack instead.
  701        * @param type the class indicating the current type of the top stack value
  702        */
  703       public void box(Type type) {
  704           if (TypeUtils.isPrimitive(type)) {
  705               if (type == Type.VOID_TYPE) {
  706                   aconst_null();
  707               } else {
  708                   Type boxed = TypeUtils.getBoxedType(type);
  709                   new_instance(boxed);
  710                   if (type.getSize() == 2) {
  711                       // Pp -> Ppo -> oPpo -> ooPpo -> ooPp -> o
  712                       dup_x2();
  713                       dup_x2();
  714                       pop();
  715                   } else {
  716                       // p -> po -> opo -> oop -> o
  717                       dup_x1();
  718                       swap();
  719                   }
  720                   invoke_constructor(boxed, new Signature(Constants.CONSTRUCTOR_NAME, Type.VOID_TYPE, new Type[]{ type }));
  721               }
  722           }
  723       }
  724       
  725       /**
  726        * If the argument is a primitive class, replaces the object
  727        * on the top of the stack with the unwrapped (primitive)
  728        * equivalent. For example, Character -> char.
  729        * @param type the class indicating the desired type of the top stack value
  730        * @return true if the value was unboxed
  731        */
  732       public void unbox(Type type) {
  733           Type t = Constants.TYPE_NUMBER;
  734           Signature sig = null;
  735           switch (type.getSort()) {
  736           case Type.VOID:
  737               return;
  738           case Type.CHAR:
  739               t = Constants.TYPE_CHARACTER;
  740               sig = CHAR_VALUE;
  741               break;
  742           case Type.BOOLEAN:
  743               t = Constants.TYPE_BOOLEAN;
  744               sig = BOOLEAN_VALUE;
  745               break;
  746           case Type.DOUBLE:
  747               sig = DOUBLE_VALUE;
  748               break;
  749           case Type.FLOAT:
  750               sig = FLOAT_VALUE;
  751               break;
  752           case Type.LONG:
  753               sig = LONG_VALUE;
  754               break;
  755           case Type.INT:
  756           case Type.SHORT:
  757           case Type.BYTE:
  758               sig = INT_VALUE;
  759           }
  760   
  761           if (sig == null) {
  762               checkcast(type);
  763           } else {
  764               checkcast(t);
  765               invoke_virtual(t, sig);
  766           }
  767       }
  768   
  769       /**
  770        * Allocates and fills an Object[] array with the arguments to the
  771        * current method. Primitive values are inserted as their boxed
  772        * (Object) equivalents.
  773        */
  774       public void create_arg_array() {
  775           /* generates:
  776              Object[] args = new Object[]{ arg1, new Integer(arg2) };
  777            */
  778   
  779           push(state.argumentTypes.length);
  780           newarray();
  781           for (int i = 0; i < state.argumentTypes.length; i++) {
  782               dup();
  783               push(i);
  784               load_arg(i);
  785               box(state.argumentTypes[i]);
  786               aastore();
  787           }
  788       }
  789   
  790   
  791       /**
  792        * Pushes a zero onto the stack if the argument is a primitive class, or a null otherwise.
  793        */
  794       public void zero_or_null(Type type) {
  795           if (TypeUtils.isPrimitive(type)) {
  796               switch (type.getSort()) {
  797               case Type.DOUBLE:
  798                   push(0d);
  799                   break;
  800               case Type.LONG:
  801                   push(0L);
  802                   break;
  803               case Type.FLOAT:
  804                   push(0f);
  805                   break;
  806               case Type.VOID:
  807                   aconst_null();
  808               default:
  809                   push(0);
  810               }
  811           } else {
  812               aconst_null();
  813           }
  814       }
  815   
  816       /**
  817        * Unboxes the object on the top of the stack. If the object is null, the
  818        * unboxed primitive value becomes zero.
  819        */
  820       public void unbox_or_zero(Type type) {
  821           if (TypeUtils.isPrimitive(type)) {
  822               if (type != Type.VOID_TYPE) {
  823                   Label nonNull = make_label();
  824                   Label end = make_label();
  825                   dup();
  826                   ifnonnull(nonNull);
  827                   pop();
  828                   zero_or_null(type);
  829                   goTo(end);
  830                   mark(nonNull);
  831                   unbox(type);
  832                   mark(end);
  833               }
  834           } else {
  835               checkcast(type);
  836           }
  837       }
  838   
  839       public void visitMaxs(int maxStack, int maxLocals) {
  840           if (!TypeUtils.isAbstract(state.access)) {
  841               mv.visitMaxs(0, 0);
  842           }
  843       }
  844   
  845       public void invoke(MethodInfo method, Type virtualType) {
  846           ClassInfo classInfo = method.getClassInfo();
  847           Type type = classInfo.getType();
  848           Signature sig = method.getSignature();
  849           if (sig.getName().equals(Constants.CONSTRUCTOR_NAME)) {
  850               invoke_constructor(type, sig);
  851           } else if (TypeUtils.isInterface(classInfo.getModifiers())) {
  852               invoke_interface(type, sig);
  853           } else if (TypeUtils.isStatic(method.getModifiers())) {
  854               invoke_static(type, sig);
  855           } else {
  856               invoke_virtual(virtualType, sig);
  857           }
  858       }
  859   
  860       public void invoke(MethodInfo method) {
  861           invoke(method, method.getClassInfo().getType());
  862       }
  863   }

Save This Page
Home » cglib-src-2.2 » net.sf.cglib.core » [javadoc | source]