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

Tue, 28 Dec 2010 15:54:52 -0800

author
ohair
date
Tue, 28 Dec 2010 15:54:52 -0800
changeset 798
4868a36f6fd8
parent 581
f2fdd52e4e87
child 816
7c537f4298fb
permissions
-rw-r--r--

6962318: Update copyright year
Reviewed-by: xdono

     1 /*
     2  * Copyright (c) 1999, 2010, Oracle and/or its affiliates. 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.  Oracle designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    22  * or visit www.oracle.com if you need additional information or have any
    23  * 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 supported API.
    47  *  If 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 a dynamically invoked method.
   143      *  @param member   The represented symbol.
   144      */
   145     Item makeDynamicItem(Symbol member) {
   146         return new DynamicItem(member);
   147     }
   149     /** Make an item representing an instance variable or method.
   150      *  @param member       The represented symbol.
   151      *  @param nonvirtual   Is the reference not virtual? (true for constructors
   152      *                      and private members).
   153      */
   154     Item makeMemberItem(Symbol member, boolean nonvirtual) {
   155         return new MemberItem(member, nonvirtual);
   156     }
   158     /** Make an item representing a literal.
   159      *  @param type     The literal's type.
   160      *  @param value    The literal's value.
   161      */
   162     Item makeImmediateItem(Type type, Object value) {
   163         return new ImmediateItem(type, value);
   164     }
   166     /** Make an item representing an assignment expression.
   167      *  @param lhs      The item representing the assignment's left hand side.
   168      */
   169     Item makeAssignItem(Item lhs) {
   170         return new AssignItem(lhs);
   171     }
   173     /** Make an item representing a conditional or unconditional jump.
   174      *  @param opcode      The jump's opcode.
   175      *  @param trueJumps   A chain encomassing all jumps that can be taken
   176      *                     if the condition evaluates to true.
   177      *  @param falseJumps  A chain encomassing all jumps that can be taken
   178      *                     if the condition evaluates to false.
   179      */
   180     CondItem makeCondItem(int opcode, Chain trueJumps, Chain falseJumps) {
   181         return new CondItem(opcode, trueJumps, falseJumps);
   182     }
   184     /** Make an item representing a conditional or unconditional jump.
   185      *  @param opcode      The jump's opcode.
   186      */
   187     CondItem makeCondItem(int opcode) {
   188         return makeCondItem(opcode, null, null);
   189     }
   191     /** The base class of all items, which implements default behavior.
   192      */
   193     abstract class Item {
   195         /** The type code of values represented by this item.
   196          */
   197         int typecode;
   199         Item(int typecode) {
   200             this.typecode = typecode;
   201         }
   203         /** Generate code to load this item onto stack.
   204          */
   205         Item load() {
   206             throw new AssertionError();
   207         }
   209         /** Generate code to store top of stack into this item.
   210          */
   211         void store() {
   212             throw new AssertionError("store unsupported: " + this);
   213         }
   215         /** Generate code to invoke method represented by this item.
   216          */
   217         Item invoke() {
   218             throw new AssertionError(this);
   219         }
   221         /** Generate code to use this item twice.
   222          */
   223         void duplicate() {}
   225         /** Generate code to avoid having to use this item.
   226          */
   227         void drop() {}
   229         /** Generate code to stash a copy of top of stack - of typecode toscode -
   230          *  under this item.
   231          */
   232         void stash(int toscode) {
   233             stackItem[toscode].duplicate();
   234         }
   236         /** Generate code to turn item into a testable condition.
   237          */
   238         CondItem mkCond() {
   239             load();
   240             return makeCondItem(ifne);
   241         }
   243         /** Generate code to coerce item to given type code.
   244          *  @param targetcode    The type code to coerce to.
   245          */
   246         Item coerce(int targetcode) {
   247             if (typecode == targetcode)
   248                 return this;
   249             else {
   250                 load();
   251                 int typecode1 = Code.truncate(typecode);
   252                 int targetcode1 = Code.truncate(targetcode);
   253                 if (typecode1 != targetcode1) {
   254                     int offset = targetcode1 > typecode1 ? targetcode1 - 1
   255                         : targetcode1;
   256                     code.emitop0(i2l + typecode1 * 3 + offset);
   257                 }
   258                 if (targetcode != targetcode1) {
   259                     code.emitop0(int2byte + targetcode - BYTEcode);
   260                 }
   261                 return stackItem[targetcode];
   262             }
   263         }
   265         /** Generate code to coerce item to given type.
   266          *  @param targettype    The type to coerce to.
   267          */
   268         Item coerce(Type targettype) {
   269             return coerce(Code.typecode(targettype));
   270         }
   272         /** Return the width of this item on stack as a number of words.
   273          */
   274         int width() {
   275             return 0;
   276         }
   278         public abstract String toString();
   279     }
   281     /** An item representing a value on stack.
   282      */
   283     class StackItem extends Item {
   285         StackItem(int typecode) {
   286             super(typecode);
   287         }
   289         Item load() {
   290             return this;
   291         }
   293         void duplicate() {
   294             code.emitop0(width() == 2 ? dup2 : dup);
   295         }
   297         void drop() {
   298             code.emitop0(width() == 2 ? pop2 : pop);
   299         }
   301         void stash(int toscode) {
   302             code.emitop0(
   303                 (width() == 2 ? dup_x2 : dup_x1) + 3 * (Code.width(toscode) - 1));
   304         }
   306         int width() {
   307             return Code.width(typecode);
   308         }
   310         public String toString() {
   311             return "stack(" + typecodeNames[typecode] + ")";
   312         }
   313     }
   315     /** An item representing an indexed expression.
   316      */
   317     class IndexedItem extends Item {
   319         IndexedItem(Type type) {
   320             super(Code.typecode(type));
   321         }
   323         Item load() {
   324             code.emitop0(iaload + typecode);
   325             return stackItem[typecode];
   326         }
   328         void store() {
   329             code.emitop0(iastore + typecode);
   330         }
   332         void duplicate() {
   333             code.emitop0(dup2);
   334         }
   336         void drop() {
   337             code.emitop0(pop2);
   338         }
   340         void stash(int toscode) {
   341             code.emitop0(dup_x2 + 3 * (Code.width(toscode) - 1));
   342         }
   344         int width() {
   345             return 2;
   346         }
   348         public String toString() {
   349             return "indexed(" + ByteCodes.typecodeNames[typecode] + ")";
   350         }
   351     }
   353     /** An item representing `this' or `super'.
   354      */
   355     class SelfItem extends Item {
   357         /** Flag which determines whether this item represents `this' or `super'.
   358          */
   359         boolean isSuper;
   361         SelfItem(boolean isSuper) {
   362             super(OBJECTcode);
   363             this.isSuper = isSuper;
   364         }
   366         Item load() {
   367             code.emitop0(aload_0);
   368             return stackItem[typecode];
   369         }
   371         public String toString() {
   372             return isSuper ? "super" : "this";
   373         }
   374     }
   376     /** An item representing a local variable.
   377      */
   378     class LocalItem extends Item {
   380         /** The variable's register.
   381          */
   382         int reg;
   384         /** The variable's type.
   385          */
   386         Type type;
   388         LocalItem(Type type, int reg) {
   389             super(Code.typecode(type));
   390             assert reg >= 0;
   391             this.type = type;
   392             this.reg = reg;
   393         }
   395         Item load() {
   396             if (reg <= 3)
   397                 code.emitop0(iload_0 + Code.truncate(typecode) * 4 + reg);
   398             else
   399                 code.emitop1w(iload + Code.truncate(typecode), reg);
   400             return stackItem[typecode];
   401         }
   403         void store() {
   404             if (reg <= 3)
   405                 code.emitop0(istore_0 + Code.truncate(typecode) * 4 + reg);
   406             else
   407                 code.emitop1w(istore + Code.truncate(typecode), reg);
   408             code.setDefined(reg);
   409         }
   411         void incr(int x) {
   412             if (typecode == INTcode && x >= -32768 && x <= 32767) {
   413                 code.emitop1w(iinc, reg, x);
   414             } else {
   415                 load();
   416                 if (x >= 0) {
   417                     makeImmediateItem(syms.intType, x).load();
   418                     code.emitop0(iadd);
   419                 } else {
   420                     makeImmediateItem(syms.intType, -x).load();
   421                     code.emitop0(isub);
   422                 }
   423                 makeStackItem(syms.intType).coerce(typecode);
   424                 store();
   425             }
   426         }
   428         public String toString() {
   429             return "localItem(type=" + type + "; reg=" + reg + ")";
   430         }
   431     }
   433     /** An item representing a static variable or method.
   434      */
   435     class StaticItem extends Item {
   437         /** The represented symbol.
   438          */
   439         Symbol member;
   441         StaticItem(Symbol member) {
   442             super(Code.typecode(member.erasure(types)));
   443             this.member = member;
   444         }
   446         Item load() {
   447             code.emitop2(getstatic, pool.put(member));
   448             return stackItem[typecode];
   449         }
   451         void store() {
   452             code.emitop2(putstatic, pool.put(member));
   453         }
   455         Item invoke() {
   456             MethodType mtype = (MethodType)member.erasure(types);
   457             int rescode = Code.typecode(mtype.restype);
   458             code.emitInvokestatic(pool.put(member), mtype);
   459             return stackItem[rescode];
   460         }
   462         public String toString() {
   463             return "static(" + member + ")";
   464         }
   465     }
   467     /** An item representing a dynamic call site.
   468      */
   469     class DynamicItem extends StaticItem {
   470         DynamicItem(Symbol member) {
   471             super(member);
   472             assert member.owner == syms.invokeDynamicType.tsym;
   473         }
   475         Item load() {
   476             assert false;
   477             return null;
   478         }
   480         void store() {
   481             assert false;
   482         }
   484         Item invoke() {
   485             // assert target.hasNativeInvokeDynamic();
   486             MethodType mtype = (MethodType)member.erasure(types);
   487             int rescode = Code.typecode(mtype.restype);
   488             ClassFile.NameAndType descr = new ClassFile.NameAndType(member.name, mtype);
   489             code.emitInvokedynamic(pool.put(descr), mtype);
   490             return stackItem[rescode];
   491         }
   493         public String toString() {
   494             return "dynamic(" + member + ")";
   495         }
   496     }
   499     /** An item representing an instance variable or method.
   500      */
   501     class MemberItem extends Item {
   503         /** The represented symbol.
   504          */
   505         Symbol member;
   507         /** Flag that determines whether or not access is virtual.
   508          */
   509         boolean nonvirtual;
   511         MemberItem(Symbol member, boolean nonvirtual) {
   512             super(Code.typecode(member.erasure(types)));
   513             this.member = member;
   514             this.nonvirtual = nonvirtual;
   515         }
   517         Item load() {
   518             code.emitop2(getfield, pool.put(member));
   519             return stackItem[typecode];
   520         }
   522         void store() {
   523             code.emitop2(putfield, pool.put(member));
   524         }
   526         Item invoke() {
   527             MethodType mtype = (MethodType)member.externalType(types);
   528             int rescode = Code.typecode(mtype.restype);
   529             if ((member.owner.flags() & Flags.INTERFACE) != 0) {
   530                 code.emitInvokeinterface(pool.put(member), mtype);
   531             } else if (nonvirtual) {
   532                 code.emitInvokespecial(pool.put(member), mtype);
   533             } else {
   534                 code.emitInvokevirtual(pool.put(member), mtype);
   535             }
   536             return stackItem[rescode];
   537         }
   539         void duplicate() {
   540             stackItem[OBJECTcode].duplicate();
   541         }
   543         void drop() {
   544             stackItem[OBJECTcode].drop();
   545         }
   547         void stash(int toscode) {
   548             stackItem[OBJECTcode].stash(toscode);
   549         }
   551         int width() {
   552             return 1;
   553         }
   555         public String toString() {
   556             return "member(" + member + (nonvirtual ? " nonvirtual)" : ")");
   557         }
   558     }
   560     /** An item representing a literal.
   561      */
   562     class ImmediateItem extends Item {
   564         /** The literal's value.
   565          */
   566         Object value;
   568         ImmediateItem(Type type, Object value) {
   569             super(Code.typecode(type));
   570             this.value = value;
   571         }
   573         private void ldc() {
   574             int idx = pool.put(value);
   575             if (typecode == LONGcode || typecode == DOUBLEcode) {
   576                 code.emitop2(ldc2w, idx);
   577             } else if (idx <= 255) {
   578                 code.emitop1(ldc1, idx);
   579             } else {
   580                 code.emitop2(ldc2, idx);
   581             }
   582         }
   584         Item load() {
   585             switch (typecode) {
   586             case INTcode: case BYTEcode: case SHORTcode: case CHARcode:
   587                 int ival = ((Number)value).intValue();
   588                 if (-1 <= ival && ival <= 5)
   589                     code.emitop0(iconst_0 + ival);
   590                 else if (Byte.MIN_VALUE <= ival && ival <= Byte.MAX_VALUE)
   591                     code.emitop1(bipush, ival);
   592                 else if (Short.MIN_VALUE <= ival && ival <= Short.MAX_VALUE)
   593                     code.emitop2(sipush, ival);
   594                 else
   595                     ldc();
   596                 break;
   597             case LONGcode:
   598                 long lval = ((Number)value).longValue();
   599                 if (lval == 0 || lval == 1)
   600                     code.emitop0(lconst_0 + (int)lval);
   601                 else
   602                     ldc();
   603                 break;
   604             case FLOATcode:
   605                 float fval = ((Number)value).floatValue();
   606                 if (isPosZero(fval) || fval == 1.0 || fval == 2.0)
   607                     code.emitop0(fconst_0 + (int)fval);
   608                 else {
   609                     ldc();
   610                 }
   611                 break;
   612             case DOUBLEcode:
   613                 double dval = ((Number)value).doubleValue();
   614                 if (isPosZero(dval) || dval == 1.0)
   615                     code.emitop0(dconst_0 + (int)dval);
   616                 else
   617                     ldc();
   618                 break;
   619             case OBJECTcode:
   620                 ldc();
   621                 break;
   622             default:
   623                 assert false;
   624             }
   625             return stackItem[typecode];
   626         }
   627         //where
   628             /** Return true iff float number is positive 0.
   629              */
   630             private boolean isPosZero(float x) {
   631                 return x == 0.0f && 1.0f / x > 0.0f;
   632             }
   633             /** Return true iff double number is positive 0.
   634              */
   635             private boolean isPosZero(double x) {
   636                 return x == 0.0d && 1.0d / x > 0.0d;
   637             }
   639         CondItem mkCond() {
   640             int ival = ((Number)value).intValue();
   641             return makeCondItem(ival != 0 ? goto_ : dontgoto);
   642         }
   644         Item coerce(int targetcode) {
   645             if (typecode == targetcode) {
   646                 return this;
   647             } else {
   648                 switch (targetcode) {
   649                 case INTcode:
   650                     if (Code.truncate(typecode) == INTcode)
   651                         return this;
   652                     else
   653                         return new ImmediateItem(
   654                             syms.intType,
   655                             ((Number)value).intValue());
   656                 case LONGcode:
   657                     return new ImmediateItem(
   658                         syms.longType,
   659                         ((Number)value).longValue());
   660                 case FLOATcode:
   661                     return new ImmediateItem(
   662                         syms.floatType,
   663                         ((Number)value).floatValue());
   664                 case DOUBLEcode:
   665                     return new ImmediateItem(
   666                         syms.doubleType,
   667                         ((Number)value).doubleValue());
   668                 case BYTEcode:
   669                     return new ImmediateItem(
   670                         syms.byteType,
   671                         (int)(byte)((Number)value).intValue());
   672                 case CHARcode:
   673                     return new ImmediateItem(
   674                         syms.charType,
   675                         (int)(char)((Number)value).intValue());
   676                 case SHORTcode:
   677                     return new ImmediateItem(
   678                         syms.shortType,
   679                         (int)(short)((Number)value).intValue());
   680                 default:
   681                     return super.coerce(targetcode);
   682                 }
   683             }
   684         }
   686         public String toString() {
   687             return "immediate(" + value + ")";
   688         }
   689     }
   691     /** An item representing an assignment expressions.
   692      */
   693     class AssignItem extends Item {
   695         /** The item representing the assignment's left hand side.
   696          */
   697         Item lhs;
   699         AssignItem(Item lhs) {
   700             super(lhs.typecode);
   701             this.lhs = lhs;
   702         }
   704         Item load() {
   705             lhs.stash(typecode);
   706             lhs.store();
   707             return stackItem[typecode];
   708         }
   710         void duplicate() {
   711             load().duplicate();
   712         }
   714         void drop() {
   715             lhs.store();
   716         }
   718         void stash(int toscode) {
   719             assert false;
   720         }
   722         int width() {
   723             return lhs.width() + Code.width(typecode);
   724         }
   726         public String toString() {
   727             return "assign(lhs = " + lhs + ")";
   728         }
   729     }
   731     /** An item representing a conditional or unconditional jump.
   732      */
   733     class CondItem extends Item {
   735         /** A chain encomassing all jumps that can be taken
   736          *  if the condition evaluates to true.
   737          */
   738         Chain trueJumps;
   740         /** A chain encomassing all jumps that can be taken
   741          *  if the condition evaluates to false.
   742          */
   743         Chain falseJumps;
   745         /** The jump's opcode.
   746          */
   747         int opcode;
   749         /*
   750          *  An abstract syntax tree of this item. It is needed
   751          *  for branch entries in 'CharacterRangeTable' attribute.
   752          */
   753         JCTree tree;
   755         CondItem(int opcode, Chain truejumps, Chain falsejumps) {
   756             super(BYTEcode);
   757             this.opcode = opcode;
   758             this.trueJumps = truejumps;
   759             this.falseJumps = falsejumps;
   760         }
   762         Item load() {
   763             Chain trueChain = null;
   764             Chain falseChain = jumpFalse();
   765             if (!isFalse()) {
   766                 code.resolve(trueJumps);
   767                 code.emitop0(iconst_1);
   768                 trueChain = code.branch(goto_);
   769             }
   770             if (falseChain != null) {
   771                 code.resolve(falseChain);
   772                 code.emitop0(iconst_0);
   773             }
   774             code.resolve(trueChain);
   775             return stackItem[typecode];
   776         }
   778         void duplicate() {
   779             load().duplicate();
   780         }
   782         void drop() {
   783             load().drop();
   784         }
   786         void stash(int toscode) {
   787             assert false;
   788         }
   790         CondItem mkCond() {
   791             return this;
   792         }
   794         Chain jumpTrue() {
   795             if (tree == null) return Code.mergeChains(trueJumps, code.branch(opcode));
   796             // we should proceed further in -Xjcov mode only
   797             int startpc = code.curPc();
   798             Chain c = Code.mergeChains(trueJumps, code.branch(opcode));
   799             code.crt.put(tree, CRTable.CRT_BRANCH_TRUE, startpc, code.curPc());
   800             return c;
   801         }
   803         Chain jumpFalse() {
   804             if (tree == null) return Code.mergeChains(falseJumps, code.branch(Code.negate(opcode)));
   805             // we should proceed further in -Xjcov mode only
   806             int startpc = code.curPc();
   807             Chain c = Code.mergeChains(falseJumps, code.branch(Code.negate(opcode)));
   808             code.crt.put(tree, CRTable.CRT_BRANCH_FALSE, startpc, code.curPc());
   809             return c;
   810         }
   812         CondItem negate() {
   813             CondItem c = new CondItem(Code.negate(opcode), falseJumps, trueJumps);
   814             c.tree = tree;
   815             return c;
   816         }
   818         int width() {
   819             // a CondItem doesn't have a size on the stack per se.
   820             throw new AssertionError();
   821         }
   823         boolean isTrue() {
   824             return falseJumps == null && opcode == goto_;
   825         }
   827         boolean isFalse() {
   828             return trueJumps == null && opcode == dontgoto;
   829         }
   831         public String toString() {
   832             return "cond(" + Code.mnem(opcode) + ")";
   833         }
   834     }
   835 }

mercurial