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

Tue, 02 Apr 2013 10:51:16 +0100

author
vromero
date
Tue, 02 Apr 2013 10:51:16 +0100
changeset 1670
29c6984a1673
parent 1393
d7d932236fee
child 2027
4932bb04c4b8
permissions
-rw-r--r--

4965689: class literal code wastes a byte
Reviewed-by: jjg

     1 /*
     2  * Copyright (c) 1999, 2013, 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.*;
    29 import com.sun.tools.javac.code.Symbol.*;
    30 import com.sun.tools.javac.code.Type.*;
    31 import com.sun.tools.javac.jvm.Code.*;
    32 import com.sun.tools.javac.tree.JCTree;
    33 import com.sun.tools.javac.util.Assert;
    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 a dynamically invoked method.
   114      *  @param member   The represented symbol.
   115      */
   116     Item makeDynamicItem(Symbol member) {
   117         return new DynamicItem(member);
   118     }
   120     /** Make an item representing an indexed expression.
   121      *  @param type    The expression's type.
   122      */
   123     Item makeIndexedItem(Type type) {
   124         return new IndexedItem(type);
   125     }
   127     /** Make an item representing a local variable.
   128      *  @param v    The represented variable.
   129      */
   130     LocalItem makeLocalItem(VarSymbol v) {
   131         return new LocalItem(v.erasure(types), v.adr);
   132     }
   134     /** Make an item representing a local anonymous variable.
   135      *  @param type  The represented variable's type.
   136      *  @param reg   The represented variable's register.
   137      */
   138     private LocalItem makeLocalItem(Type type, int reg) {
   139         return new LocalItem(type, reg);
   140     }
   142     /** Make an item representing a static variable or method.
   143      *  @param member   The represented symbol.
   144      */
   145     Item makeStaticItem(Symbol member) {
   146         return new StaticItem(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.check(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         }
   474         Item load() {
   475             assert false;
   476             return null;
   477         }
   479         void store() {
   480             assert false;
   481         }
   483         Item invoke() {
   484             // assert target.hasNativeInvokeDynamic();
   485             MethodType mtype = (MethodType)member.erasure(types);
   486             int rescode = Code.typecode(mtype.restype);
   487             code.emitInvokedynamic(pool.put(member), mtype);
   488             return stackItem[rescode];
   489         }
   491         public String toString() {
   492             return "dynamic(" + member + ")";
   493         }
   494     }
   496     /** An item representing an instance variable or method.
   497      */
   498     class MemberItem extends Item {
   500         /** The represented symbol.
   501          */
   502         Symbol member;
   504         /** Flag that determines whether or not access is virtual.
   505          */
   506         boolean nonvirtual;
   508         MemberItem(Symbol member, boolean nonvirtual) {
   509             super(Code.typecode(member.erasure(types)));
   510             this.member = member;
   511             this.nonvirtual = nonvirtual;
   512         }
   514         Item load() {
   515             code.emitop2(getfield, pool.put(member));
   516             return stackItem[typecode];
   517         }
   519         void store() {
   520             code.emitop2(putfield, pool.put(member));
   521         }
   523         Item invoke() {
   524             MethodType mtype = (MethodType)member.externalType(types);
   525             int rescode = Code.typecode(mtype.restype);
   526             if ((member.owner.flags() & Flags.INTERFACE) != 0 && !nonvirtual) {
   527                 code.emitInvokeinterface(pool.put(member), mtype);
   528             } else if (nonvirtual) {
   529                 code.emitInvokespecial(pool.put(member), mtype);
   530             } else {
   531                 code.emitInvokevirtual(pool.put(member), mtype);
   532             }
   533             return stackItem[rescode];
   534         }
   536         void duplicate() {
   537             stackItem[OBJECTcode].duplicate();
   538         }
   540         void drop() {
   541             stackItem[OBJECTcode].drop();
   542         }
   544         void stash(int toscode) {
   545             stackItem[OBJECTcode].stash(toscode);
   546         }
   548         int width() {
   549             return 1;
   550         }
   552         public String toString() {
   553             return "member(" + member + (nonvirtual ? " nonvirtual)" : ")");
   554         }
   555     }
   557     /** An item representing a literal.
   558      */
   559     class ImmediateItem extends Item {
   561         /** The literal's value.
   562          */
   563         Object value;
   565         ImmediateItem(Type type, Object value) {
   566             super(Code.typecode(type));
   567             this.value = value;
   568         }
   570         private void ldc() {
   571             int idx = pool.put(value);
   572             if (typecode == LONGcode || typecode == DOUBLEcode) {
   573                 code.emitop2(ldc2w, idx);
   574             } else {
   575                 code.emitLdc(idx);
   576             }
   577         }
   579         Item load() {
   580             switch (typecode) {
   581             case INTcode: case BYTEcode: case SHORTcode: case CHARcode:
   582                 int ival = ((Number)value).intValue();
   583                 if (-1 <= ival && ival <= 5)
   584                     code.emitop0(iconst_0 + ival);
   585                 else if (Byte.MIN_VALUE <= ival && ival <= Byte.MAX_VALUE)
   586                     code.emitop1(bipush, ival);
   587                 else if (Short.MIN_VALUE <= ival && ival <= Short.MAX_VALUE)
   588                     code.emitop2(sipush, ival);
   589                 else
   590                     ldc();
   591                 break;
   592             case LONGcode:
   593                 long lval = ((Number)value).longValue();
   594                 if (lval == 0 || lval == 1)
   595                     code.emitop0(lconst_0 + (int)lval);
   596                 else
   597                     ldc();
   598                 break;
   599             case FLOATcode:
   600                 float fval = ((Number)value).floatValue();
   601                 if (isPosZero(fval) || fval == 1.0 || fval == 2.0)
   602                     code.emitop0(fconst_0 + (int)fval);
   603                 else {
   604                     ldc();
   605                 }
   606                 break;
   607             case DOUBLEcode:
   608                 double dval = ((Number)value).doubleValue();
   609                 if (isPosZero(dval) || dval == 1.0)
   610                     code.emitop0(dconst_0 + (int)dval);
   611                 else
   612                     ldc();
   613                 break;
   614             case OBJECTcode:
   615                 ldc();
   616                 break;
   617             default:
   618                 Assert.error();
   619             }
   620             return stackItem[typecode];
   621         }
   622         //where
   623             /** Return true iff float number is positive 0.
   624              */
   625             private boolean isPosZero(float x) {
   626                 return x == 0.0f && 1.0f / x > 0.0f;
   627             }
   628             /** Return true iff double number is positive 0.
   629              */
   630             private boolean isPosZero(double x) {
   631                 return x == 0.0d && 1.0d / x > 0.0d;
   632             }
   634         CondItem mkCond() {
   635             int ival = ((Number)value).intValue();
   636             return makeCondItem(ival != 0 ? goto_ : dontgoto);
   637         }
   639         Item coerce(int targetcode) {
   640             if (typecode == targetcode) {
   641                 return this;
   642             } else {
   643                 switch (targetcode) {
   644                 case INTcode:
   645                     if (Code.truncate(typecode) == INTcode)
   646                         return this;
   647                     else
   648                         return new ImmediateItem(
   649                             syms.intType,
   650                             ((Number)value).intValue());
   651                 case LONGcode:
   652                     return new ImmediateItem(
   653                         syms.longType,
   654                         ((Number)value).longValue());
   655                 case FLOATcode:
   656                     return new ImmediateItem(
   657                         syms.floatType,
   658                         ((Number)value).floatValue());
   659                 case DOUBLEcode:
   660                     return new ImmediateItem(
   661                         syms.doubleType,
   662                         ((Number)value).doubleValue());
   663                 case BYTEcode:
   664                     return new ImmediateItem(
   665                         syms.byteType,
   666                         (int)(byte)((Number)value).intValue());
   667                 case CHARcode:
   668                     return new ImmediateItem(
   669                         syms.charType,
   670                         (int)(char)((Number)value).intValue());
   671                 case SHORTcode:
   672                     return new ImmediateItem(
   673                         syms.shortType,
   674                         (int)(short)((Number)value).intValue());
   675                 default:
   676                     return super.coerce(targetcode);
   677                 }
   678             }
   679         }
   681         public String toString() {
   682             return "immediate(" + value + ")";
   683         }
   684     }
   686     /** An item representing an assignment expressions.
   687      */
   688     class AssignItem extends Item {
   690         /** The item representing the assignment's left hand side.
   691          */
   692         Item lhs;
   694         AssignItem(Item lhs) {
   695             super(lhs.typecode);
   696             this.lhs = lhs;
   697         }
   699         Item load() {
   700             lhs.stash(typecode);
   701             lhs.store();
   702             return stackItem[typecode];
   703         }
   705         void duplicate() {
   706             load().duplicate();
   707         }
   709         void drop() {
   710             lhs.store();
   711         }
   713         void stash(int toscode) {
   714             Assert.error();
   715         }
   717         int width() {
   718             return lhs.width() + Code.width(typecode);
   719         }
   721         public String toString() {
   722             return "assign(lhs = " + lhs + ")";
   723         }
   724     }
   726     /** An item representing a conditional or unconditional jump.
   727      */
   728     class CondItem extends Item {
   730         /** A chain encomassing all jumps that can be taken
   731          *  if the condition evaluates to true.
   732          */
   733         Chain trueJumps;
   735         /** A chain encomassing all jumps that can be taken
   736          *  if the condition evaluates to false.
   737          */
   738         Chain falseJumps;
   740         /** The jump's opcode.
   741          */
   742         int opcode;
   744         /*
   745          *  An abstract syntax tree of this item. It is needed
   746          *  for branch entries in 'CharacterRangeTable' attribute.
   747          */
   748         JCTree tree;
   750         CondItem(int opcode, Chain truejumps, Chain falsejumps) {
   751             super(BYTEcode);
   752             this.opcode = opcode;
   753             this.trueJumps = truejumps;
   754             this.falseJumps = falsejumps;
   755         }
   757         Item load() {
   758             Chain trueChain = null;
   759             Chain falseChain = jumpFalse();
   760             if (!isFalse()) {
   761                 code.resolve(trueJumps);
   762                 code.emitop0(iconst_1);
   763                 trueChain = code.branch(goto_);
   764             }
   765             if (falseChain != null) {
   766                 code.resolve(falseChain);
   767                 code.emitop0(iconst_0);
   768             }
   769             code.resolve(trueChain);
   770             return stackItem[typecode];
   771         }
   773         void duplicate() {
   774             load().duplicate();
   775         }
   777         void drop() {
   778             load().drop();
   779         }
   781         void stash(int toscode) {
   782             Assert.error();
   783         }
   785         CondItem mkCond() {
   786             return this;
   787         }
   789         Chain jumpTrue() {
   790             if (tree == null) return Code.mergeChains(trueJumps, code.branch(opcode));
   791             // we should proceed further in -Xjcov mode only
   792             int startpc = code.curPc();
   793             Chain c = Code.mergeChains(trueJumps, code.branch(opcode));
   794             code.crt.put(tree, CRTable.CRT_BRANCH_TRUE, startpc, code.curPc());
   795             return c;
   796         }
   798         Chain jumpFalse() {
   799             if (tree == null) return Code.mergeChains(falseJumps, code.branch(Code.negate(opcode)));
   800             // we should proceed further in -Xjcov mode only
   801             int startpc = code.curPc();
   802             Chain c = Code.mergeChains(falseJumps, code.branch(Code.negate(opcode)));
   803             code.crt.put(tree, CRTable.CRT_BRANCH_FALSE, startpc, code.curPc());
   804             return c;
   805         }
   807         CondItem negate() {
   808             CondItem c = new CondItem(Code.negate(opcode), falseJumps, trueJumps);
   809             c.tree = tree;
   810             return c;
   811         }
   813         int width() {
   814             // a CondItem doesn't have a size on the stack per se.
   815             throw new AssertionError();
   816         }
   818         boolean isTrue() {
   819             return falseJumps == null && opcode == goto_;
   820         }
   822         boolean isFalse() {
   823             return trueJumps == null && opcode == dontgoto;
   824         }
   826         public String toString() {
   827             return "cond(" + Code.mnem(opcode) + ")";
   828         }
   829     }
   830 }

mercurial