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

Sun, 17 Feb 2013 16:44:55 -0500

author
dholmes
date
Sun, 17 Feb 2013 16:44:55 -0500
changeset 1571
af8417e590f4
parent 1393
d7d932236fee
child 1670
29c6984a1673
permissions
-rw-r--r--

Merge

     1 /*
     2  * Copyright (c) 1999, 2012, 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 if (idx <= 255) {
   575                 code.emitop1(ldc1, idx);
   576             } else {
   577                 code.emitop2(ldc2, idx);
   578             }
   579         }
   581         Item load() {
   582             switch (typecode) {
   583             case INTcode: case BYTEcode: case SHORTcode: case CHARcode:
   584                 int ival = ((Number)value).intValue();
   585                 if (-1 <= ival && ival <= 5)
   586                     code.emitop0(iconst_0 + ival);
   587                 else if (Byte.MIN_VALUE <= ival && ival <= Byte.MAX_VALUE)
   588                     code.emitop1(bipush, ival);
   589                 else if (Short.MIN_VALUE <= ival && ival <= Short.MAX_VALUE)
   590                     code.emitop2(sipush, ival);
   591                 else
   592                     ldc();
   593                 break;
   594             case LONGcode:
   595                 long lval = ((Number)value).longValue();
   596                 if (lval == 0 || lval == 1)
   597                     code.emitop0(lconst_0 + (int)lval);
   598                 else
   599                     ldc();
   600                 break;
   601             case FLOATcode:
   602                 float fval = ((Number)value).floatValue();
   603                 if (isPosZero(fval) || fval == 1.0 || fval == 2.0)
   604                     code.emitop0(fconst_0 + (int)fval);
   605                 else {
   606                     ldc();
   607                 }
   608                 break;
   609             case DOUBLEcode:
   610                 double dval = ((Number)value).doubleValue();
   611                 if (isPosZero(dval) || dval == 1.0)
   612                     code.emitop0(dconst_0 + (int)dval);
   613                 else
   614                     ldc();
   615                 break;
   616             case OBJECTcode:
   617                 ldc();
   618                 break;
   619             default:
   620                 Assert.error();
   621             }
   622             return stackItem[typecode];
   623         }
   624         //where
   625             /** Return true iff float number is positive 0.
   626              */
   627             private boolean isPosZero(float x) {
   628                 return x == 0.0f && 1.0f / x > 0.0f;
   629             }
   630             /** Return true iff double number is positive 0.
   631              */
   632             private boolean isPosZero(double x) {
   633                 return x == 0.0d && 1.0d / x > 0.0d;
   634             }
   636         CondItem mkCond() {
   637             int ival = ((Number)value).intValue();
   638             return makeCondItem(ival != 0 ? goto_ : dontgoto);
   639         }
   641         Item coerce(int targetcode) {
   642             if (typecode == targetcode) {
   643                 return this;
   644             } else {
   645                 switch (targetcode) {
   646                 case INTcode:
   647                     if (Code.truncate(typecode) == INTcode)
   648                         return this;
   649                     else
   650                         return new ImmediateItem(
   651                             syms.intType,
   652                             ((Number)value).intValue());
   653                 case LONGcode:
   654                     return new ImmediateItem(
   655                         syms.longType,
   656                         ((Number)value).longValue());
   657                 case FLOATcode:
   658                     return new ImmediateItem(
   659                         syms.floatType,
   660                         ((Number)value).floatValue());
   661                 case DOUBLEcode:
   662                     return new ImmediateItem(
   663                         syms.doubleType,
   664                         ((Number)value).doubleValue());
   665                 case BYTEcode:
   666                     return new ImmediateItem(
   667                         syms.byteType,
   668                         (int)(byte)((Number)value).intValue());
   669                 case CHARcode:
   670                     return new ImmediateItem(
   671                         syms.charType,
   672                         (int)(char)((Number)value).intValue());
   673                 case SHORTcode:
   674                     return new ImmediateItem(
   675                         syms.shortType,
   676                         (int)(short)((Number)value).intValue());
   677                 default:
   678                     return super.coerce(targetcode);
   679                 }
   680             }
   681         }
   683         public String toString() {
   684             return "immediate(" + value + ")";
   685         }
   686     }
   688     /** An item representing an assignment expressions.
   689      */
   690     class AssignItem extends Item {
   692         /** The item representing the assignment's left hand side.
   693          */
   694         Item lhs;
   696         AssignItem(Item lhs) {
   697             super(lhs.typecode);
   698             this.lhs = lhs;
   699         }
   701         Item load() {
   702             lhs.stash(typecode);
   703             lhs.store();
   704             return stackItem[typecode];
   705         }
   707         void duplicate() {
   708             load().duplicate();
   709         }
   711         void drop() {
   712             lhs.store();
   713         }
   715         void stash(int toscode) {
   716             Assert.error();
   717         }
   719         int width() {
   720             return lhs.width() + Code.width(typecode);
   721         }
   723         public String toString() {
   724             return "assign(lhs = " + lhs + ")";
   725         }
   726     }
   728     /** An item representing a conditional or unconditional jump.
   729      */
   730     class CondItem extends Item {
   732         /** A chain encomassing all jumps that can be taken
   733          *  if the condition evaluates to true.
   734          */
   735         Chain trueJumps;
   737         /** A chain encomassing all jumps that can be taken
   738          *  if the condition evaluates to false.
   739          */
   740         Chain falseJumps;
   742         /** The jump's opcode.
   743          */
   744         int opcode;
   746         /*
   747          *  An abstract syntax tree of this item. It is needed
   748          *  for branch entries in 'CharacterRangeTable' attribute.
   749          */
   750         JCTree tree;
   752         CondItem(int opcode, Chain truejumps, Chain falsejumps) {
   753             super(BYTEcode);
   754             this.opcode = opcode;
   755             this.trueJumps = truejumps;
   756             this.falseJumps = falsejumps;
   757         }
   759         Item load() {
   760             Chain trueChain = null;
   761             Chain falseChain = jumpFalse();
   762             if (!isFalse()) {
   763                 code.resolve(trueJumps);
   764                 code.emitop0(iconst_1);
   765                 trueChain = code.branch(goto_);
   766             }
   767             if (falseChain != null) {
   768                 code.resolve(falseChain);
   769                 code.emitop0(iconst_0);
   770             }
   771             code.resolve(trueChain);
   772             return stackItem[typecode];
   773         }
   775         void duplicate() {
   776             load().duplicate();
   777         }
   779         void drop() {
   780             load().drop();
   781         }
   783         void stash(int toscode) {
   784             Assert.error();
   785         }
   787         CondItem mkCond() {
   788             return this;
   789         }
   791         Chain jumpTrue() {
   792             if (tree == null) return Code.mergeChains(trueJumps, code.branch(opcode));
   793             // we should proceed further in -Xjcov mode only
   794             int startpc = code.curPc();
   795             Chain c = Code.mergeChains(trueJumps, code.branch(opcode));
   796             code.crt.put(tree, CRTable.CRT_BRANCH_TRUE, startpc, code.curPc());
   797             return c;
   798         }
   800         Chain jumpFalse() {
   801             if (tree == null) return Code.mergeChains(falseJumps, code.branch(Code.negate(opcode)));
   802             // we should proceed further in -Xjcov mode only
   803             int startpc = code.curPc();
   804             Chain c = Code.mergeChains(falseJumps, code.branch(Code.negate(opcode)));
   805             code.crt.put(tree, CRTable.CRT_BRANCH_FALSE, startpc, code.curPc());
   806             return c;
   807         }
   809         CondItem negate() {
   810             CondItem c = new CondItem(Code.negate(opcode), falseJumps, trueJumps);
   811             c.tree = tree;
   812             return c;
   813         }
   815         int width() {
   816             // a CondItem doesn't have a size on the stack per se.
   817             throw new AssertionError();
   818         }
   820         boolean isTrue() {
   821             return falseJumps == null && opcode == goto_;
   822         }
   824         boolean isFalse() {
   825             return trueJumps == null && opcode == dontgoto;
   826         }
   828         public String toString() {
   829             return "cond(" + Code.mnem(opcode) + ")";
   830         }
   831     }
   832 }

mercurial