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

Sat, 01 Dec 2007 00:00:00 +0000

author
duke
date
Sat, 01 Dec 2007 00:00:00 +0000
changeset 1
9a66ca7c79fa
child 104
5e89c4ca637c
permissions
-rw-r--r--

Initial load

     1 /*
     2  * Copyright 1999-2007 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.util.*;
    29 import com.sun.tools.javac.code.*;
    31 import com.sun.tools.javac.code.Symbol.*;
    32 import com.sun.tools.javac.code.Type.*;
    33 import com.sun.tools.javac.jvm.Code.*;
    34 import com.sun.tools.javac.tree.JCTree;
    36 import static com.sun.tools.javac.code.TypeTags.*;
    37 import static com.sun.tools.javac.jvm.ByteCodes.*;
    39 /** A helper class for code generation. Items are objects
    40  *  that stand for addressable entities in the bytecode. Each item
    41  *  supports a fixed protocol for loading the item on the stack, storing
    42  *  into it, converting it into a jump condition, and several others.
    43  *  There are many individual forms of items, such as local, static,
    44  *  indexed, or instance variables, values on the top of stack, the
    45  *  special values this or super, etc. Individual items are represented as
    46  *  inner classes in class Items.
    47  *
    48  *  <p><b>This is NOT part of any API supported by Sun Microsystems.  If
    49  *  you write code that depends on this, you do so at your own risk.
    50  *  This code and its internal interfaces are subject to change or
    51  *  deletion without notice.</b>
    52  */
    53 public class Items {
    55     /** The current constant pool.
    56      */
    57     Pool pool;
    59     /** The current code buffer.
    60      */
    61     Code code;
    63     /** The current symbol table.
    64      */
    65     Symtab syms;
    67     /** Type utilities. */
    68     Types types;
    70     /** Items that exist only once (flyweight pattern).
    71      */
    72     private final Item voidItem;
    73     private final Item thisItem;
    74     private final Item superItem;
    75     private final Item[] stackItem = new Item[TypeCodeCount];
    77     public Items(Pool pool, Code code, Symtab syms, Types types) {
    78         this.code = code;
    79         this.pool = pool;
    80         this.types = types;
    81         voidItem = new Item(VOIDcode) {
    82                 public String toString() { return "void"; }
    83             };
    84         thisItem = new SelfItem(false);
    85         superItem = new SelfItem(true);
    86         for (int i = 0; i < VOIDcode; i++) stackItem[i] = new StackItem(i);
    87         stackItem[VOIDcode] = voidItem;
    88         this.syms = syms;
    89     }
    91     /** Make a void item
    92      */
    93     Item makeVoidItem() {
    94         return voidItem;
    95     }
    96     /** Make an item representing `this'.
    97      */
    98     Item makeThisItem() {
    99         return thisItem;
   100     }
   102     /** Make an item representing `super'.
   103      */
   104     Item makeSuperItem() {
   105         return superItem;
   106     }
   108     /** Make an item representing a value on stack.
   109      *  @param type    The value's type.
   110      */
   111     Item makeStackItem(Type type) {
   112         return stackItem[Code.typecode(type)];
   113     }
   115     /** Make an item representing an indexed expression.
   116      *  @param type    The expression's type.
   117      */
   118     Item makeIndexedItem(Type type) {
   119         return new IndexedItem(type);
   120     }
   122     /** Make an item representing a local variable.
   123      *  @param v    The represented variable.
   124      */
   125     LocalItem makeLocalItem(VarSymbol v) {
   126         return new LocalItem(v.erasure(types), v.adr);
   127     }
   129     /** Make an item representing a local anonymous variable.
   130      *  @param type  The represented variable's type.
   131      *  @param reg   The represented variable's register.
   132      */
   133     private LocalItem makeLocalItem(Type type, int reg) {
   134         return new LocalItem(type, reg);
   135     }
   137     /** Make an item representing a static variable or method.
   138      *  @param member   The represented symbol.
   139      */
   140     Item makeStaticItem(Symbol member) {
   141         return new StaticItem(member);
   142     }
   144     /** Make an item representing an instance variable or method.
   145      *  @param member       The represented symbol.
   146      *  @param nonvirtual   Is the reference not virtual? (true for constructors
   147      *                      and private members).
   148      */
   149     Item makeMemberItem(Symbol member, boolean nonvirtual) {
   150         return new MemberItem(member, nonvirtual);
   151     }
   153     /** Make an item representing a literal.
   154      *  @param type     The literal's type.
   155      *  @param value    The literal's value.
   156      */
   157     Item makeImmediateItem(Type type, Object value) {
   158         return new ImmediateItem(type, value);
   159     }
   161     /** Make an item representing an assignment expression.
   162      *  @param lhs      The item representing the assignment's left hand side.
   163      */
   164     Item makeAssignItem(Item lhs) {
   165         return new AssignItem(lhs);
   166     }
   168     /** Make an item representing a conditional or unconditional jump.
   169      *  @param opcode      The jump's opcode.
   170      *  @param trueJumps   A chain encomassing all jumps that can be taken
   171      *                     if the condition evaluates to true.
   172      *  @param falseJumps  A chain encomassing all jumps that can be taken
   173      *                     if the condition evaluates to false.
   174      */
   175     CondItem makeCondItem(int opcode, Chain trueJumps, Chain falseJumps) {
   176         return new CondItem(opcode, trueJumps, falseJumps);
   177     }
   179     /** Make an item representing a conditional or unconditional jump.
   180      *  @param opcode      The jump's opcode.
   181      */
   182     CondItem makeCondItem(int opcode) {
   183         return makeCondItem(opcode, null, null);
   184     }
   186     /** The base class of all items, which implements default behavior.
   187      */
   188     abstract class Item {
   190         /** The type code of values represented by this item.
   191          */
   192         int typecode;
   194         Item(int typecode) {
   195             this.typecode = typecode;
   196         }
   198         /** Generate code to load this item onto stack.
   199          */
   200         Item load() {
   201             throw new AssertionError();
   202         }
   204         /** Generate code to store top of stack into this item.
   205          */
   206         void store() {
   207             throw new AssertionError("store unsupported: " + this);
   208         }
   210         /** Generate code to invoke method represented by this item.
   211          */
   212         Item invoke() {
   213             throw new AssertionError(this);
   214         }
   216         /** Generate code to use this item twice.
   217          */
   218         void duplicate() {}
   220         /** Generate code to avoid having to use this item.
   221          */
   222         void drop() {}
   224         /** Generate code to stash a copy of top of stack - of typecode toscode -
   225          *  under this item.
   226          */
   227         void stash(int toscode) {
   228             stackItem[toscode].duplicate();
   229         }
   231         /** Generate code to turn item into a testable condition.
   232          */
   233         CondItem mkCond() {
   234             load();
   235             return makeCondItem(ifne);
   236         }
   238         /** Generate code to coerce item to given type code.
   239          *  @param targetcode    The type code to coerce to.
   240          */
   241         Item coerce(int targetcode) {
   242             if (typecode == targetcode)
   243                 return this;
   244             else {
   245                 load();
   246                 int typecode1 = Code.truncate(typecode);
   247                 int targetcode1 = Code.truncate(targetcode);
   248                 if (typecode1 != targetcode1) {
   249                     int offset = targetcode1 > typecode1 ? targetcode1 - 1
   250                         : targetcode1;
   251                     code.emitop0(i2l + typecode1 * 3 + offset);
   252                 }
   253                 if (targetcode != targetcode1) {
   254                     code.emitop0(int2byte + targetcode - BYTEcode);
   255                 }
   256                 return stackItem[targetcode];
   257             }
   258         }
   260         /** Generate code to coerce item to given type.
   261          *  @param targettype    The type to coerce to.
   262          */
   263         Item coerce(Type targettype) {
   264             return coerce(Code.typecode(targettype));
   265         }
   267         /** Return the width of this item on stack as a number of words.
   268          */
   269         int width() {
   270             return 0;
   271         }
   273         public abstract String toString();
   274     }
   276     /** An item representing a value on stack.
   277      */
   278     class StackItem extends Item {
   280         StackItem(int typecode) {
   281             super(typecode);
   282         }
   284         Item load() {
   285             return this;
   286         }
   288         void duplicate() {
   289             code.emitop0(width() == 2 ? dup2 : dup);
   290         }
   292         void drop() {
   293             code.emitop0(width() == 2 ? pop2 : pop);
   294         }
   296         void stash(int toscode) {
   297             code.emitop0(
   298                 (width() == 2 ? dup_x2 : dup_x1) + 3 * (Code.width(toscode) - 1));
   299         }
   301         int width() {
   302             return Code.width(typecode);
   303         }
   305         public String toString() {
   306             return "stack(" + typecodeNames[typecode] + ")";
   307         }
   308     }
   310     /** An item representing an indexed expression.
   311      */
   312     class IndexedItem extends Item {
   314         IndexedItem(Type type) {
   315             super(Code.typecode(type));
   316         }
   318         Item load() {
   319             code.emitop0(iaload + typecode);
   320             return stackItem[typecode];
   321         }
   323         void store() {
   324             code.emitop0(iastore + typecode);
   325         }
   327         void duplicate() {
   328             code.emitop0(dup2);
   329         }
   331         void drop() {
   332             code.emitop0(pop2);
   333         }
   335         void stash(int toscode) {
   336             code.emitop0(dup_x2 + 3 * (Code.width(toscode) - 1));
   337         }
   339         int width() {
   340             return 2;
   341         }
   343         public String toString() {
   344             return "indexed(" + ByteCodes.typecodeNames[typecode] + ")";
   345         }
   346     }
   348     /** An item representing `this' or `super'.
   349      */
   350     class SelfItem extends Item {
   352         /** Flag which determines whether this item represents `this' or `super'.
   353          */
   354         boolean isSuper;
   356         SelfItem(boolean isSuper) {
   357             super(OBJECTcode);
   358             this.isSuper = isSuper;
   359         }
   361         Item load() {
   362             code.emitop0(aload_0);
   363             return stackItem[typecode];
   364         }
   366         public String toString() {
   367             return isSuper ? "super" : "this";
   368         }
   369     }
   371     /** An item representing a local variable.
   372      */
   373     class LocalItem extends Item {
   375         /** The variable's register.
   376          */
   377         int reg;
   379         /** The variable's type.
   380          */
   381         Type type;
   383         LocalItem(Type type, int reg) {
   384             super(Code.typecode(type));
   385             assert reg >= 0;
   386             this.type = type;
   387             this.reg = reg;
   388         }
   390         Item load() {
   391             if (reg <= 3)
   392                 code.emitop0(iload_0 + Code.truncate(typecode) * 4 + reg);
   393             else
   394                 code.emitop1w(iload + Code.truncate(typecode), reg);
   395             return stackItem[typecode];
   396         }
   398         void store() {
   399             if (reg <= 3)
   400                 code.emitop0(istore_0 + Code.truncate(typecode) * 4 + reg);
   401             else
   402                 code.emitop1w(istore + Code.truncate(typecode), reg);
   403             code.setDefined(reg);
   404         }
   406         void incr(int x) {
   407             if (typecode == INTcode && x >= -32768 && x <= 32767) {
   408                 code.emitop1w(iinc, reg, x);
   409             } else {
   410                 load();
   411                 if (x >= 0) {
   412                     makeImmediateItem(syms.intType, x).load();
   413                     code.emitop0(iadd);
   414                 } else {
   415                     makeImmediateItem(syms.intType, -x).load();
   416                     code.emitop0(isub);
   417                 }
   418                 makeStackItem(syms.intType).coerce(typecode);
   419                 store();
   420             }
   421         }
   423         public String toString() {
   424             return "localItem(type=" + type + "; reg=" + reg + ")";
   425         }
   426     }
   428     /** An item representing a static variable or method.
   429      */
   430     class StaticItem extends Item {
   432         /** The represented symbol.
   433          */
   434         Symbol member;
   436         StaticItem(Symbol member) {
   437             super(Code.typecode(member.erasure(types)));
   438             this.member = member;
   439         }
   441         Item load() {
   442             code.emitop2(getstatic, pool.put(member));
   443             return stackItem[typecode];
   444         }
   446         void store() {
   447             code.emitop2(putstatic, pool.put(member));
   448         }
   450         Item invoke() {
   451             MethodType mtype = (MethodType)member.erasure(types);
   452             int argsize = Code.width(mtype.argtypes);
   453             int rescode = Code.typecode(mtype.restype);
   454             int sdiff = Code.width(rescode) - argsize;
   455             code.emitInvokestatic(pool.put(member), mtype);
   456             return stackItem[rescode];
   457         }
   459         public String toString() {
   460             return "static(" + member + ")";
   461         }
   462     }
   464     /** An item representing an instance variable or method.
   465      */
   466     class MemberItem extends Item {
   468         /** The represented symbol.
   469          */
   470         Symbol member;
   472         /** Flag that determines whether or not access is virtual.
   473          */
   474         boolean nonvirtual;
   476         MemberItem(Symbol member, boolean nonvirtual) {
   477             super(Code.typecode(member.erasure(types)));
   478             this.member = member;
   479             this.nonvirtual = nonvirtual;
   480         }
   482         Item load() {
   483             code.emitop2(getfield, pool.put(member));
   484             return stackItem[typecode];
   485         }
   487         void store() {
   488             code.emitop2(putfield, pool.put(member));
   489         }
   491         Item invoke() {
   492             MethodType mtype = (MethodType)member.externalType(types);
   493             int rescode = Code.typecode(mtype.restype);
   494             if ((member.owner.flags() & Flags.INTERFACE) != 0) {
   495                 code.emitInvokeinterface(pool.put(member), mtype);
   496             } else if (nonvirtual) {
   497                 code.emitInvokespecial(pool.put(member), mtype);
   498             } else {
   499                 code.emitInvokevirtual(pool.put(member), mtype);
   500             }
   501             return stackItem[rescode];
   502         }
   504         void duplicate() {
   505             stackItem[OBJECTcode].duplicate();
   506         }
   508         void drop() {
   509             stackItem[OBJECTcode].drop();
   510         }
   512         void stash(int toscode) {
   513             stackItem[OBJECTcode].stash(toscode);
   514         }
   516         int width() {
   517             return 1;
   518         }
   520         public String toString() {
   521             return "member(" + member + (nonvirtual ? " nonvirtual)" : ")");
   522         }
   523     }
   525     /** An item representing a literal.
   526      */
   527     class ImmediateItem extends Item {
   529         /** The literal's value.
   530          */
   531         Object value;
   533         ImmediateItem(Type type, Object value) {
   534             super(Code.typecode(type));
   535             this.value = value;
   536         }
   538         private void ldc() {
   539             int idx = pool.put(value);
   540             if (typecode == LONGcode || typecode == DOUBLEcode) {
   541                 code.emitop2(ldc2w, idx);
   542             } else if (idx <= 255) {
   543                 code.emitop1(ldc1, idx);
   544             } else {
   545                 code.emitop2(ldc2, idx);
   546             }
   547         }
   549         Item load() {
   550             switch (typecode) {
   551             case INTcode: case BYTEcode: case SHORTcode: case CHARcode:
   552                 int ival = ((Number)value).intValue();
   553                 if (-1 <= ival && ival <= 5)
   554                     code.emitop0(iconst_0 + ival);
   555                 else if (Byte.MIN_VALUE <= ival && ival <= Byte.MAX_VALUE)
   556                     code.emitop1(bipush, ival);
   557                 else if (Short.MIN_VALUE <= ival && ival <= Short.MAX_VALUE)
   558                     code.emitop2(sipush, ival);
   559                 else
   560                     ldc();
   561                 break;
   562             case LONGcode:
   563                 long lval = ((Number)value).longValue();
   564                 if (lval == 0 || lval == 1)
   565                     code.emitop0(lconst_0 + (int)lval);
   566                 else
   567                     ldc();
   568                 break;
   569             case FLOATcode:
   570                 float fval = ((Number)value).floatValue();
   571                 if (isPosZero(fval) || fval == 1.0 || fval == 2.0)
   572                     code.emitop0(fconst_0 + (int)fval);
   573                 else {
   574                     ldc();
   575                 }
   576                 break;
   577             case DOUBLEcode:
   578                 double dval = ((Number)value).doubleValue();
   579                 if (isPosZero(dval) || dval == 1.0)
   580                     code.emitop0(dconst_0 + (int)dval);
   581                 else
   582                     ldc();
   583                 break;
   584             case OBJECTcode:
   585                 ldc();
   586                 break;
   587             default:
   588                 assert false;
   589             }
   590             return stackItem[typecode];
   591         }
   592         //where
   593             /** Return true iff float number is positive 0.
   594              */
   595             private boolean isPosZero(float x) {
   596                 return x == 0.0f && 1.0f / x > 0.0f;
   597             }
   598             /** Return true iff double number is positive 0.
   599              */
   600             private boolean isPosZero(double x) {
   601                 return x == 0.0d && 1.0d / x > 0.0d;
   602             }
   604         CondItem mkCond() {
   605             int ival = ((Number)value).intValue();
   606             return makeCondItem(ival != 0 ? goto_ : dontgoto);
   607         }
   609         Item coerce(int targetcode) {
   610             if (typecode == targetcode) {
   611                 return this;
   612             } else {
   613                 switch (targetcode) {
   614                 case INTcode:
   615                     if (Code.truncate(typecode) == INTcode)
   616                         return this;
   617                     else
   618                         return new ImmediateItem(
   619                             syms.intType,
   620                             ((Number)value).intValue());
   621                 case LONGcode:
   622                     return new ImmediateItem(
   623                         syms.longType,
   624                         ((Number)value).longValue());
   625                 case FLOATcode:
   626                     return new ImmediateItem(
   627                         syms.floatType,
   628                         ((Number)value).floatValue());
   629                 case DOUBLEcode:
   630                     return new ImmediateItem(
   631                         syms.doubleType,
   632                         ((Number)value).doubleValue());
   633                 case BYTEcode:
   634                     return new ImmediateItem(
   635                         syms.byteType,
   636                         (int)(byte)((Number)value).intValue());
   637                 case CHARcode:
   638                     return new ImmediateItem(
   639                         syms.charType,
   640                         (int)(char)((Number)value).intValue());
   641                 case SHORTcode:
   642                     return new ImmediateItem(
   643                         syms.shortType,
   644                         (int)(short)((Number)value).intValue());
   645                 default:
   646                     return super.coerce(targetcode);
   647                 }
   648             }
   649         }
   651         public String toString() {
   652             return "immediate(" + value + ")";
   653         }
   654     }
   656     /** An item representing an assignment expressions.
   657      */
   658     class AssignItem extends Item {
   660         /** The item representing the assignment's left hand side.
   661          */
   662         Item lhs;
   664         AssignItem(Item lhs) {
   665             super(lhs.typecode);
   666             this.lhs = lhs;
   667         }
   669         Item load() {
   670             lhs.stash(typecode);
   671             lhs.store();
   672             return stackItem[typecode];
   673         }
   675         void duplicate() {
   676             load().duplicate();
   677         }
   679         void drop() {
   680             lhs.store();
   681         }
   683         void stash(int toscode) {
   684             assert false;
   685         }
   687         int width() {
   688             return lhs.width() + Code.width(typecode);
   689         }
   691         public String toString() {
   692             return "assign(lhs = " + lhs + ")";
   693         }
   694     }
   696     /** An item representing a conditional or unconditional jump.
   697      */
   698     class CondItem extends Item {
   700         /** A chain encomassing all jumps that can be taken
   701          *  if the condition evaluates to true.
   702          */
   703         Chain trueJumps;
   705         /** A chain encomassing all jumps that can be taken
   706          *  if the condition evaluates to false.
   707          */
   708         Chain falseJumps;
   710         /** The jump's opcode.
   711          */
   712         int opcode;
   714         /*
   715          *  An abstract syntax tree of this item. It is needed
   716          *  for branch entries in 'CharacterRangeTable' attribute.
   717          */
   718         JCTree tree;
   720         CondItem(int opcode, Chain truejumps, Chain falsejumps) {
   721             super(BYTEcode);
   722             this.opcode = opcode;
   723             this.trueJumps = truejumps;
   724             this.falseJumps = falsejumps;
   725         }
   727         Item load() {
   728             Chain trueChain = null;
   729             Chain falseChain = jumpFalse();
   730             if (!isFalse()) {
   731                 code.resolve(trueJumps);
   732                 code.emitop0(iconst_1);
   733                 trueChain = code.branch(goto_);
   734             }
   735             if (falseChain != null) {
   736                 code.resolve(falseChain);
   737                 code.emitop0(iconst_0);
   738             }
   739             code.resolve(trueChain);
   740             return stackItem[typecode];
   741         }
   743         void duplicate() {
   744             load().duplicate();
   745         }
   747         void drop() {
   748             load().drop();
   749         }
   751         void stash(int toscode) {
   752             assert false;
   753         }
   755         CondItem mkCond() {
   756             return this;
   757         }
   759         Chain jumpTrue() {
   760             if (tree == null) return code.mergeChains(trueJumps, code.branch(opcode));
   761             // we should proceed further in -Xjcov mode only
   762             int startpc = code.curPc();
   763             Chain c = code.mergeChains(trueJumps, code.branch(opcode));
   764             code.crt.put(tree, CRTable.CRT_BRANCH_TRUE, startpc, code.curPc());
   765             return c;
   766         }
   768         Chain jumpFalse() {
   769             if (tree == null) return code.mergeChains(falseJumps, code.branch(code.negate(opcode)));
   770             // we should proceed further in -Xjcov mode only
   771             int startpc = code.curPc();
   772             Chain c = code.mergeChains(falseJumps, code.branch(code.negate(opcode)));
   773             code.crt.put(tree, CRTable.CRT_BRANCH_FALSE, startpc, code.curPc());
   774             return c;
   775         }
   777         CondItem negate() {
   778             CondItem c = new CondItem(code.negate(opcode), falseJumps, trueJumps);
   779             c.tree = tree;
   780             return c;
   781         }
   783         int width() {
   784             // a CondItem doesn't have a size on the stack per se.
   785             throw new AssertionError();
   786         }
   788         boolean isTrue() {
   789             return falseJumps == null && opcode == goto_;
   790         }
   792         boolean isFalse() {
   793             return trueJumps == null && opcode == dontgoto;
   794         }
   796         public String toString() {
   797             return "cond(" + Code.mnem(opcode) + ")";
   798         }
   799     }
   800 }

mercurial