src/share/classes/com/sun/tools/javac/jvm/Items.java

Thu, 02 Oct 2008 19:58:40 -0700

author
xdono
date
Thu, 02 Oct 2008 19:58:40 -0700
changeset 117
24a47c3062fe
parent 104
5e89c4ca637c
child 267
e2722bd43f3a
permissions
-rw-r--r--

6754988: Update copyright year
Summary: Update for files that have been modified starting July 2008
Reviewed-by: ohair, tbell

     1 /*
     2  * Copyright 1999-2008 Sun Microsystems, Inc.  All Rights Reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Sun designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Sun in the LICENSE file that accompanied this code.
    10  *
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    14  * version 2 for more details (a copy is included in the LICENSE file that
    15  * accompanied this code).
    16  *
    17  * You should have received a copy of the GNU General Public License version
    18  * 2 along with this work; if not, write to the Free Software Foundation,
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    20  *
    21  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
    22  * CA 95054 USA or visit www.sun.com if you need additional information or
    23  * have any questions.
    24  */
    26 package com.sun.tools.javac.jvm;
    28 import com.sun.tools.javac.code.*;
    30 import com.sun.tools.javac.code.Symbol.*;
    31 import com.sun.tools.javac.code.Type.*;
    32 import com.sun.tools.javac.jvm.Code.*;
    33 import com.sun.tools.javac.tree.JCTree;
    35 import static com.sun.tools.javac.jvm.ByteCodes.*;
    37 /** A helper class for code generation. Items are objects
    38  *  that stand for addressable entities in the bytecode. Each item
    39  *  supports a fixed protocol for loading the item on the stack, storing
    40  *  into it, converting it into a jump condition, and several others.
    41  *  There are many individual forms of items, such as local, static,
    42  *  indexed, or instance variables, values on the top of stack, the
    43  *  special values this or super, etc. Individual items are represented as
    44  *  inner classes in class Items.
    45  *
    46  *  <p><b>This is NOT part of any API supported by Sun Microsystems.  If
    47  *  you write code that depends on this, you do so at your own risk.
    48  *  This code and its internal interfaces are subject to change or
    49  *  deletion without notice.</b>
    50  */
    51 public class Items {
    53     /** The current constant pool.
    54      */
    55     Pool pool;
    57     /** The current code buffer.
    58      */
    59     Code code;
    61     /** The current symbol table.
    62      */
    63     Symtab syms;
    65     /** Type utilities. */
    66     Types types;
    68     /** Items that exist only once (flyweight pattern).
    69      */
    70     private final Item voidItem;
    71     private final Item thisItem;
    72     private final Item superItem;
    73     private final Item[] stackItem = new Item[TypeCodeCount];
    75     public Items(Pool pool, Code code, Symtab syms, Types types) {
    76         this.code = code;
    77         this.pool = pool;
    78         this.types = types;
    79         voidItem = new Item(VOIDcode) {
    80                 public String toString() { return "void"; }
    81             };
    82         thisItem = new SelfItem(false);
    83         superItem = new SelfItem(true);
    84         for (int i = 0; i < VOIDcode; i++) stackItem[i] = new StackItem(i);
    85         stackItem[VOIDcode] = voidItem;
    86         this.syms = syms;
    87     }
    89     /** Make a void item
    90      */
    91     Item makeVoidItem() {
    92         return voidItem;
    93     }
    94     /** Make an item representing `this'.
    95      */
    96     Item makeThisItem() {
    97         return thisItem;
    98     }
   100     /** Make an item representing `super'.
   101      */
   102     Item makeSuperItem() {
   103         return superItem;
   104     }
   106     /** Make an item representing a value on stack.
   107      *  @param type    The value's type.
   108      */
   109     Item makeStackItem(Type type) {
   110         return stackItem[Code.typecode(type)];
   111     }
   113     /** Make an item representing an indexed expression.
   114      *  @param type    The expression's type.
   115      */
   116     Item makeIndexedItem(Type type) {
   117         return new IndexedItem(type);
   118     }
   120     /** Make an item representing a local variable.
   121      *  @param v    The represented variable.
   122      */
   123     LocalItem makeLocalItem(VarSymbol v) {
   124         return new LocalItem(v.erasure(types), v.adr);
   125     }
   127     /** Make an item representing a local anonymous variable.
   128      *  @param type  The represented variable's type.
   129      *  @param reg   The represented variable's register.
   130      */
   131     private LocalItem makeLocalItem(Type type, int reg) {
   132         return new LocalItem(type, reg);
   133     }
   135     /** Make an item representing a static variable or method.
   136      *  @param member   The represented symbol.
   137      */
   138     Item makeStaticItem(Symbol member) {
   139         return new StaticItem(member);
   140     }
   142     /** Make an item representing an instance variable or method.
   143      *  @param member       The represented symbol.
   144      *  @param nonvirtual   Is the reference not virtual? (true for constructors
   145      *                      and private members).
   146      */
   147     Item makeMemberItem(Symbol member, boolean nonvirtual) {
   148         return new MemberItem(member, nonvirtual);
   149     }
   151     /** Make an item representing a literal.
   152      *  @param type     The literal's type.
   153      *  @param value    The literal's value.
   154      */
   155     Item makeImmediateItem(Type type, Object value) {
   156         return new ImmediateItem(type, value);
   157     }
   159     /** Make an item representing an assignment expression.
   160      *  @param lhs      The item representing the assignment's left hand side.
   161      */
   162     Item makeAssignItem(Item lhs) {
   163         return new AssignItem(lhs);
   164     }
   166     /** Make an item representing a conditional or unconditional jump.
   167      *  @param opcode      The jump's opcode.
   168      *  @param trueJumps   A chain encomassing all jumps that can be taken
   169      *                     if the condition evaluates to true.
   170      *  @param falseJumps  A chain encomassing all jumps that can be taken
   171      *                     if the condition evaluates to false.
   172      */
   173     CondItem makeCondItem(int opcode, Chain trueJumps, Chain falseJumps) {
   174         return new CondItem(opcode, trueJumps, falseJumps);
   175     }
   177     /** Make an item representing a conditional or unconditional jump.
   178      *  @param opcode      The jump's opcode.
   179      */
   180     CondItem makeCondItem(int opcode) {
   181         return makeCondItem(opcode, null, null);
   182     }
   184     /** The base class of all items, which implements default behavior.
   185      */
   186     abstract class Item {
   188         /** The type code of values represented by this item.
   189          */
   190         int typecode;
   192         Item(int typecode) {
   193             this.typecode = typecode;
   194         }
   196         /** Generate code to load this item onto stack.
   197          */
   198         Item load() {
   199             throw new AssertionError();
   200         }
   202         /** Generate code to store top of stack into this item.
   203          */
   204         void store() {
   205             throw new AssertionError("store unsupported: " + this);
   206         }
   208         /** Generate code to invoke method represented by this item.
   209          */
   210         Item invoke() {
   211             throw new AssertionError(this);
   212         }
   214         /** Generate code to use this item twice.
   215          */
   216         void duplicate() {}
   218         /** Generate code to avoid having to use this item.
   219          */
   220         void drop() {}
   222         /** Generate code to stash a copy of top of stack - of typecode toscode -
   223          *  under this item.
   224          */
   225         void stash(int toscode) {
   226             stackItem[toscode].duplicate();
   227         }
   229         /** Generate code to turn item into a testable condition.
   230          */
   231         CondItem mkCond() {
   232             load();
   233             return makeCondItem(ifne);
   234         }
   236         /** Generate code to coerce item to given type code.
   237          *  @param targetcode    The type code to coerce to.
   238          */
   239         Item coerce(int targetcode) {
   240             if (typecode == targetcode)
   241                 return this;
   242             else {
   243                 load();
   244                 int typecode1 = Code.truncate(typecode);
   245                 int targetcode1 = Code.truncate(targetcode);
   246                 if (typecode1 != targetcode1) {
   247                     int offset = targetcode1 > typecode1 ? targetcode1 - 1
   248                         : targetcode1;
   249                     code.emitop0(i2l + typecode1 * 3 + offset);
   250                 }
   251                 if (targetcode != targetcode1) {
   252                     code.emitop0(int2byte + targetcode - BYTEcode);
   253                 }
   254                 return stackItem[targetcode];
   255             }
   256         }
   258         /** Generate code to coerce item to given type.
   259          *  @param targettype    The type to coerce to.
   260          */
   261         Item coerce(Type targettype) {
   262             return coerce(Code.typecode(targettype));
   263         }
   265         /** Return the width of this item on stack as a number of words.
   266          */
   267         int width() {
   268             return 0;
   269         }
   271         public abstract String toString();
   272     }
   274     /** An item representing a value on stack.
   275      */
   276     class StackItem extends Item {
   278         StackItem(int typecode) {
   279             super(typecode);
   280         }
   282         Item load() {
   283             return this;
   284         }
   286         void duplicate() {
   287             code.emitop0(width() == 2 ? dup2 : dup);
   288         }
   290         void drop() {
   291             code.emitop0(width() == 2 ? pop2 : pop);
   292         }
   294         void stash(int toscode) {
   295             code.emitop0(
   296                 (width() == 2 ? dup_x2 : dup_x1) + 3 * (Code.width(toscode) - 1));
   297         }
   299         int width() {
   300             return Code.width(typecode);
   301         }
   303         public String toString() {
   304             return "stack(" + typecodeNames[typecode] + ")";
   305         }
   306     }
   308     /** An item representing an indexed expression.
   309      */
   310     class IndexedItem extends Item {
   312         IndexedItem(Type type) {
   313             super(Code.typecode(type));
   314         }
   316         Item load() {
   317             code.emitop0(iaload + typecode);
   318             return stackItem[typecode];
   319         }
   321         void store() {
   322             code.emitop0(iastore + typecode);
   323         }
   325         void duplicate() {
   326             code.emitop0(dup2);
   327         }
   329         void drop() {
   330             code.emitop0(pop2);
   331         }
   333         void stash(int toscode) {
   334             code.emitop0(dup_x2 + 3 * (Code.width(toscode) - 1));
   335         }
   337         int width() {
   338             return 2;
   339         }
   341         public String toString() {
   342             return "indexed(" + ByteCodes.typecodeNames[typecode] + ")";
   343         }
   344     }
   346     /** An item representing `this' or `super'.
   347      */
   348     class SelfItem extends Item {
   350         /** Flag which determines whether this item represents `this' or `super'.
   351          */
   352         boolean isSuper;
   354         SelfItem(boolean isSuper) {
   355             super(OBJECTcode);
   356             this.isSuper = isSuper;
   357         }
   359         Item load() {
   360             code.emitop0(aload_0);
   361             return stackItem[typecode];
   362         }
   364         public String toString() {
   365             return isSuper ? "super" : "this";
   366         }
   367     }
   369     /** An item representing a local variable.
   370      */
   371     class LocalItem extends Item {
   373         /** The variable's register.
   374          */
   375         int reg;
   377         /** The variable's type.
   378          */
   379         Type type;
   381         LocalItem(Type type, int reg) {
   382             super(Code.typecode(type));
   383             assert reg >= 0;
   384             this.type = type;
   385             this.reg = reg;
   386         }
   388         Item load() {
   389             if (reg <= 3)
   390                 code.emitop0(iload_0 + Code.truncate(typecode) * 4 + reg);
   391             else
   392                 code.emitop1w(iload + Code.truncate(typecode), reg);
   393             return stackItem[typecode];
   394         }
   396         void store() {
   397             if (reg <= 3)
   398                 code.emitop0(istore_0 + Code.truncate(typecode) * 4 + reg);
   399             else
   400                 code.emitop1w(istore + Code.truncate(typecode), reg);
   401             code.setDefined(reg);
   402         }
   404         void incr(int x) {
   405             if (typecode == INTcode && x >= -32768 && x <= 32767) {
   406                 code.emitop1w(iinc, reg, x);
   407             } else {
   408                 load();
   409                 if (x >= 0) {
   410                     makeImmediateItem(syms.intType, x).load();
   411                     code.emitop0(iadd);
   412                 } else {
   413                     makeImmediateItem(syms.intType, -x).load();
   414                     code.emitop0(isub);
   415                 }
   416                 makeStackItem(syms.intType).coerce(typecode);
   417                 store();
   418             }
   419         }
   421         public String toString() {
   422             return "localItem(type=" + type + "; reg=" + reg + ")";
   423         }
   424     }
   426     /** An item representing a static variable or method.
   427      */
   428     class StaticItem extends Item {
   430         /** The represented symbol.
   431          */
   432         Symbol member;
   434         StaticItem(Symbol member) {
   435             super(Code.typecode(member.erasure(types)));
   436             this.member = member;
   437         }
   439         Item load() {
   440             code.emitop2(getstatic, pool.put(member));
   441             return stackItem[typecode];
   442         }
   444         void store() {
   445             code.emitop2(putstatic, pool.put(member));
   446         }
   448         Item invoke() {
   449             MethodType mtype = (MethodType)member.erasure(types);
   450             int rescode = Code.typecode(mtype.restype);
   451             code.emitInvokestatic(pool.put(member), mtype);
   452             return stackItem[rescode];
   453         }
   455         public String toString() {
   456             return "static(" + member + ")";
   457         }
   458     }
   460     /** An item representing an instance variable or method.
   461      */
   462     class MemberItem extends Item {
   464         /** The represented symbol.
   465          */
   466         Symbol member;
   468         /** Flag that determines whether or not access is virtual.
   469          */
   470         boolean nonvirtual;
   472         MemberItem(Symbol member, boolean nonvirtual) {
   473             super(Code.typecode(member.erasure(types)));
   474             this.member = member;
   475             this.nonvirtual = nonvirtual;
   476         }
   478         Item load() {
   479             code.emitop2(getfield, pool.put(member));
   480             return stackItem[typecode];
   481         }
   483         void store() {
   484             code.emitop2(putfield, pool.put(member));
   485         }
   487         Item invoke() {
   488             MethodType mtype = (MethodType)member.externalType(types);
   489             int rescode = Code.typecode(mtype.restype);
   490             if ((member.owner.flags() & Flags.INTERFACE) != 0) {
   491                 code.emitInvokeinterface(pool.put(member), mtype);
   492             } else if (nonvirtual) {
   493                 code.emitInvokespecial(pool.put(member), mtype);
   494             } else {
   495                 code.emitInvokevirtual(pool.put(member), mtype);
   496             }
   497             return stackItem[rescode];
   498         }
   500         void duplicate() {
   501             stackItem[OBJECTcode].duplicate();
   502         }
   504         void drop() {
   505             stackItem[OBJECTcode].drop();
   506         }
   508         void stash(int toscode) {
   509             stackItem[OBJECTcode].stash(toscode);
   510         }
   512         int width() {
   513             return 1;
   514         }
   516         public String toString() {
   517             return "member(" + member + (nonvirtual ? " nonvirtual)" : ")");
   518         }
   519     }
   521     /** An item representing a literal.
   522      */
   523     class ImmediateItem extends Item {
   525         /** The literal's value.
   526          */
   527         Object value;
   529         ImmediateItem(Type type, Object value) {
   530             super(Code.typecode(type));
   531             this.value = value;
   532         }
   534         private void ldc() {
   535             int idx = pool.put(value);
   536             if (typecode == LONGcode || typecode == DOUBLEcode) {
   537                 code.emitop2(ldc2w, idx);
   538             } else if (idx <= 255) {
   539                 code.emitop1(ldc1, idx);
   540             } else {
   541                 code.emitop2(ldc2, idx);
   542             }
   543         }
   545         Item load() {
   546             switch (typecode) {
   547             case INTcode: case BYTEcode: case SHORTcode: case CHARcode:
   548                 int ival = ((Number)value).intValue();
   549                 if (-1 <= ival && ival <= 5)
   550                     code.emitop0(iconst_0 + ival);
   551                 else if (Byte.MIN_VALUE <= ival && ival <= Byte.MAX_VALUE)
   552                     code.emitop1(bipush, ival);
   553                 else if (Short.MIN_VALUE <= ival && ival <= Short.MAX_VALUE)
   554                     code.emitop2(sipush, ival);
   555                 else
   556                     ldc();
   557                 break;
   558             case LONGcode:
   559                 long lval = ((Number)value).longValue();
   560                 if (lval == 0 || lval == 1)
   561                     code.emitop0(lconst_0 + (int)lval);
   562                 else
   563                     ldc();
   564                 break;
   565             case FLOATcode:
   566                 float fval = ((Number)value).floatValue();
   567                 if (isPosZero(fval) || fval == 1.0 || fval == 2.0)
   568                     code.emitop0(fconst_0 + (int)fval);
   569                 else {
   570                     ldc();
   571                 }
   572                 break;
   573             case DOUBLEcode:
   574                 double dval = ((Number)value).doubleValue();
   575                 if (isPosZero(dval) || dval == 1.0)
   576                     code.emitop0(dconst_0 + (int)dval);
   577                 else
   578                     ldc();
   579                 break;
   580             case OBJECTcode:
   581                 ldc();
   582                 break;
   583             default:
   584                 assert false;
   585             }
   586             return stackItem[typecode];
   587         }
   588         //where
   589             /** Return true iff float number is positive 0.
   590              */
   591             private boolean isPosZero(float x) {
   592                 return x == 0.0f && 1.0f / x > 0.0f;
   593             }
   594             /** Return true iff double number is positive 0.
   595              */
   596             private boolean isPosZero(double x) {
   597                 return x == 0.0d && 1.0d / x > 0.0d;
   598             }
   600         CondItem mkCond() {
   601             int ival = ((Number)value).intValue();
   602             return makeCondItem(ival != 0 ? goto_ : dontgoto);
   603         }
   605         Item coerce(int targetcode) {
   606             if (typecode == targetcode) {
   607                 return this;
   608             } else {
   609                 switch (targetcode) {
   610                 case INTcode:
   611                     if (Code.truncate(typecode) == INTcode)
   612                         return this;
   613                     else
   614                         return new ImmediateItem(
   615                             syms.intType,
   616                             ((Number)value).intValue());
   617                 case LONGcode:
   618                     return new ImmediateItem(
   619                         syms.longType,
   620                         ((Number)value).longValue());
   621                 case FLOATcode:
   622                     return new ImmediateItem(
   623                         syms.floatType,
   624                         ((Number)value).floatValue());
   625                 case DOUBLEcode:
   626                     return new ImmediateItem(
   627                         syms.doubleType,
   628                         ((Number)value).doubleValue());
   629                 case BYTEcode:
   630                     return new ImmediateItem(
   631                         syms.byteType,
   632                         (int)(byte)((Number)value).intValue());
   633                 case CHARcode:
   634                     return new ImmediateItem(
   635                         syms.charType,
   636                         (int)(char)((Number)value).intValue());
   637                 case SHORTcode:
   638                     return new ImmediateItem(
   639                         syms.shortType,
   640                         (int)(short)((Number)value).intValue());
   641                 default:
   642                     return super.coerce(targetcode);
   643                 }
   644             }
   645         }
   647         public String toString() {
   648             return "immediate(" + value + ")";
   649         }
   650     }
   652     /** An item representing an assignment expressions.
   653      */
   654     class AssignItem extends Item {
   656         /** The item representing the assignment's left hand side.
   657          */
   658         Item lhs;
   660         AssignItem(Item lhs) {
   661             super(lhs.typecode);
   662             this.lhs = lhs;
   663         }
   665         Item load() {
   666             lhs.stash(typecode);
   667             lhs.store();
   668             return stackItem[typecode];
   669         }
   671         void duplicate() {
   672             load().duplicate();
   673         }
   675         void drop() {
   676             lhs.store();
   677         }
   679         void stash(int toscode) {
   680             assert false;
   681         }
   683         int width() {
   684             return lhs.width() + Code.width(typecode);
   685         }
   687         public String toString() {
   688             return "assign(lhs = " + lhs + ")";
   689         }
   690     }
   692     /** An item representing a conditional or unconditional jump.
   693      */
   694     class CondItem extends Item {
   696         /** A chain encomassing all jumps that can be taken
   697          *  if the condition evaluates to true.
   698          */
   699         Chain trueJumps;
   701         /** A chain encomassing all jumps that can be taken
   702          *  if the condition evaluates to false.
   703          */
   704         Chain falseJumps;
   706         /** The jump's opcode.
   707          */
   708         int opcode;
   710         /*
   711          *  An abstract syntax tree of this item. It is needed
   712          *  for branch entries in 'CharacterRangeTable' attribute.
   713          */
   714         JCTree tree;
   716         CondItem(int opcode, Chain truejumps, Chain falsejumps) {
   717             super(BYTEcode);
   718             this.opcode = opcode;
   719             this.trueJumps = truejumps;
   720             this.falseJumps = falsejumps;
   721         }
   723         Item load() {
   724             Chain trueChain = null;
   725             Chain falseChain = jumpFalse();
   726             if (!isFalse()) {
   727                 code.resolve(trueJumps);
   728                 code.emitop0(iconst_1);
   729                 trueChain = code.branch(goto_);
   730             }
   731             if (falseChain != null) {
   732                 code.resolve(falseChain);
   733                 code.emitop0(iconst_0);
   734             }
   735             code.resolve(trueChain);
   736             return stackItem[typecode];
   737         }
   739         void duplicate() {
   740             load().duplicate();
   741         }
   743         void drop() {
   744             load().drop();
   745         }
   747         void stash(int toscode) {
   748             assert false;
   749         }
   751         CondItem mkCond() {
   752             return this;
   753         }
   755         Chain jumpTrue() {
   756             if (tree == null) return code.mergeChains(trueJumps, code.branch(opcode));
   757             // we should proceed further in -Xjcov mode only
   758             int startpc = code.curPc();
   759             Chain c = code.mergeChains(trueJumps, code.branch(opcode));
   760             code.crt.put(tree, CRTable.CRT_BRANCH_TRUE, startpc, code.curPc());
   761             return c;
   762         }
   764         Chain jumpFalse() {
   765             if (tree == null) return code.mergeChains(falseJumps, code.branch(code.negate(opcode)));
   766             // we should proceed further in -Xjcov mode only
   767             int startpc = code.curPc();
   768             Chain c = code.mergeChains(falseJumps, code.branch(code.negate(opcode)));
   769             code.crt.put(tree, CRTable.CRT_BRANCH_FALSE, startpc, code.curPc());
   770             return c;
   771         }
   773         CondItem negate() {
   774             CondItem c = new CondItem(code.negate(opcode), falseJumps, trueJumps);
   775             c.tree = tree;
   776             return c;
   777         }
   779         int width() {
   780             // a CondItem doesn't have a size on the stack per se.
   781             throw new AssertionError();
   782         }
   784         boolean isTrue() {
   785             return falseJumps == null && opcode == goto_;
   786         }
   788         boolean isFalse() {
   789             return trueJumps == null && opcode == dontgoto;
   790         }
   792         public String toString() {
   793             return "cond(" + Code.mnem(opcode) + ")";
   794         }
   795     }
   796 }

mercurial