001    /*
002     * Copyright 1999-2008 Sun Microsystems, Inc.  All Rights Reserved.
003     * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004     *
005     * This code is free software; you can redistribute it and/or modify it
006     * under the terms of the GNU General Public License version 2 only, as
007     * published by the Free Software Foundation.  Sun designates this
008     * particular file as subject to the "Classpath" exception as provided
009     * by Sun in the LICENSE file that accompanied this code.
010     *
011     * This code is distributed in the hope that it will be useful, but WITHOUT
012     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013     * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
014     * version 2 for more details (a copy is included in the LICENSE file that
015     * accompanied this code).
016     *
017     * You should have received a copy of the GNU General Public License version
018     * 2 along with this work; if not, write to the Free Software Foundation,
019     * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020     *
021     * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022     * CA 95054 USA or visit www.sun.com if you need additional information or
023     * have any questions.
024     */
025    
026    package com.sun.tools.javac.jvm;
027    
028    import com.sun.tools.javac.code.*;
029    
030    import com.sun.tools.javac.code.Symbol.*;
031    import com.sun.tools.javac.code.Type.*;
032    import com.sun.tools.javac.jvm.Code.*;
033    import com.sun.tools.javac.tree.JCTree;
034    
035    import static com.sun.tools.javac.jvm.ByteCodes.*;
036    
037    /** A helper class for code generation. Items are objects
038     *  that stand for addressable entities in the bytecode. Each item
039     *  supports a fixed protocol for loading the item on the stack, storing
040     *  into it, converting it into a jump condition, and several others.
041     *  There are many individual forms of items, such as local, static,
042     *  indexed, or instance variables, values on the top of stack, the
043     *  special values this or super, etc. Individual items are represented as
044     *  inner classes in class Items.
045     *
046     *  <p><b>This is NOT part of any API supported by Sun Microsystems.  If
047     *  you write code that depends on this, you do so at your own risk.
048     *  This code and its internal interfaces are subject to change or
049     *  deletion without notice.</b>
050     */
051    public class Items {
052    
053        /** The current constant pool.
054         */
055        Pool pool;
056    
057        /** The current code buffer.
058         */
059        Code code;
060    
061        /** The current symbol table.
062         */
063        Symtab syms;
064    
065        /** Type utilities. */
066        Types types;
067    
068        /** Items that exist only once (flyweight pattern).
069         */
070        private final Item voidItem;
071        private final Item thisItem;
072        private final Item superItem;
073        private final Item[] stackItem = new Item[TypeCodeCount];
074    
075        public Items(Pool pool, Code code, Symtab syms, Types types) {
076            this.code = code;
077            this.pool = pool;
078            this.types = types;
079            voidItem = new Item(VOIDcode) {
080                    public String toString() { return "void"; }
081                };
082            thisItem = new SelfItem(false);
083            superItem = new SelfItem(true);
084            for (int i = 0; i < VOIDcode; i++) stackItem[i] = new StackItem(i);
085            stackItem[VOIDcode] = voidItem;
086            this.syms = syms;
087        }
088    
089        /** Make a void item
090         */
091        Item makeVoidItem() {
092            return voidItem;
093        }
094        /** Make an item representing `this'.
095         */
096        Item makeThisItem() {
097            return thisItem;
098        }
099    
100        /** Make an item representing `super'.
101         */
102        Item makeSuperItem() {
103            return superItem;
104        }
105    
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        }
112    
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        }
119    
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        }
126    
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        }
134    
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        }
141    
142        /** Make an item representing an instance variable or method.
143         *  @param member       The represented symbol.
144         *  @param nonvirtual   Is the reference not virtual? (true for constructors
145         *                      and private members).
146         */
147        Item makeMemberItem(Symbol member, boolean nonvirtual) {
148            return new MemberItem(member, nonvirtual);
149        }
150    
151        /** Make an item representing a literal.
152         *  @param type     The literal's type.
153         *  @param value    The literal's value.
154         */
155        Item makeImmediateItem(Type type, Object value) {
156            return new ImmediateItem(type, value);
157        }
158    
159        /** Make an item representing an assignment expression.
160         *  @param lhs      The item representing the assignment's left hand side.
161         */
162        Item makeAssignItem(Item lhs) {
163            return new AssignItem(lhs);
164        }
165    
166        /** Make an item representing a conditional or unconditional jump.
167         *  @param opcode      The jump's opcode.
168         *  @param trueJumps   A chain encomassing all jumps that can be taken
169         *                     if the condition evaluates to true.
170         *  @param falseJumps  A chain encomassing all jumps that can be taken
171         *                     if the condition evaluates to false.
172         */
173        CondItem makeCondItem(int opcode, Chain trueJumps, Chain falseJumps) {
174            return new CondItem(opcode, trueJumps, falseJumps);
175        }
176    
177        /** Make an item representing a conditional or unconditional jump.
178         *  @param opcode      The jump's opcode.
179         */
180        CondItem makeCondItem(int opcode) {
181            return makeCondItem(opcode, null, null);
182        }
183    
184        /** The base class of all items, which implements default behavior.
185         */
186        abstract class Item {
187    
188            /** The type code of values represented by this item.
189             */
190            int typecode;
191    
192            Item(int typecode) {
193                this.typecode = typecode;
194            }
195    
196            /** Generate code to load this item onto stack.
197             */
198            Item load() {
199                throw new AssertionError();
200            }
201    
202            /** Generate code to store top of stack into this item.
203             */
204            void store() {
205                throw new AssertionError("store unsupported: " + this);
206            }
207    
208            /** Generate code to invoke method represented by this item.
209             */
210            Item invoke() {
211                throw new AssertionError(this);
212            }
213    
214            /** Generate code to use this item twice.
215             */
216            void duplicate() {}
217    
218            /** Generate code to avoid having to use this item.
219             */
220            void drop() {}
221    
222            /** Generate code to stash a copy of top of stack - of typecode toscode -
223             *  under this item.
224             */
225            void stash(int toscode) {
226                stackItem[toscode].duplicate();
227            }
228    
229            /** Generate code to turn item into a testable condition.
230             */
231            CondItem mkCond() {
232                load();
233                return makeCondItem(ifne);
234            }
235    
236            /** Generate code to coerce item to given type code.
237             *  @param targetcode    The type code to coerce to.
238             */
239            Item coerce(int targetcode) {
240                if (typecode == targetcode)
241                    return this;
242                else {
243                    load();
244                    int typecode1 = Code.truncate(typecode);
245                    int targetcode1 = Code.truncate(targetcode);
246                    if (typecode1 != targetcode1) {
247                        int offset = targetcode1 > typecode1 ? targetcode1 - 1
248                            : targetcode1;
249                        code.emitop0(i2l + typecode1 * 3 + offset);
250                    }
251                    if (targetcode != targetcode1) {
252                        code.emitop0(int2byte + targetcode - BYTEcode);
253                    }
254                    return stackItem[targetcode];
255                }
256            }
257    
258            /** Generate code to coerce item to given type.
259             *  @param targettype    The type to coerce to.
260             */
261            Item coerce(Type targettype) {
262                return coerce(Code.typecode(targettype));
263            }
264    
265            /** Return the width of this item on stack as a number of words.
266             */
267            int width() {
268                return 0;
269            }
270    
271            public abstract String toString();
272        }
273    
274        /** An item representing a value on stack.
275         */
276        class StackItem extends Item {
277    
278            StackItem(int typecode) {
279                super(typecode);
280            }
281    
282            Item load() {
283                return this;
284            }
285    
286            void duplicate() {
287                code.emitop0(width() == 2 ? dup2 : dup);
288            }
289    
290            void drop() {
291                code.emitop0(width() == 2 ? pop2 : pop);
292            }
293    
294            void stash(int toscode) {
295                code.emitop0(
296                    (width() == 2 ? dup_x2 : dup_x1) + 3 * (Code.width(toscode) - 1));
297            }
298    
299            int width() {
300                return Code.width(typecode);
301            }
302    
303            public String toString() {
304                return "stack(" + typecodeNames[typecode] + ")";
305            }
306        }
307    
308        /** An item representing an indexed expression.
309         */
310        class IndexedItem extends Item {
311    
312            IndexedItem(Type type) {
313                super(Code.typecode(type));
314            }
315    
316            Item load() {
317                code.emitop0(iaload + typecode);
318                return stackItem[typecode];
319            }
320    
321            void store() {
322                code.emitop0(iastore + typecode);
323            }
324    
325            void duplicate() {
326                code.emitop0(dup2);
327            }
328    
329            void drop() {
330                code.emitop0(pop2);
331            }
332    
333            void stash(int toscode) {
334                code.emitop0(dup_x2 + 3 * (Code.width(toscode) - 1));
335            }
336    
337            int width() {
338                return 2;
339            }
340    
341            public String toString() {
342                return "indexed(" + ByteCodes.typecodeNames[typecode] + ")";
343            }
344        }
345    
346        /** An item representing `this' or `super'.
347         */
348        class SelfItem extends Item {
349    
350            /** Flag which determines whether this item represents `this' or `super'.
351             */
352            boolean isSuper;
353    
354            SelfItem(boolean isSuper) {
355                super(OBJECTcode);
356                this.isSuper = isSuper;
357            }
358    
359            Item load() {
360                code.emitop0(aload_0);
361                return stackItem[typecode];
362            }
363    
364            public String toString() {
365                return isSuper ? "super" : "this";
366            }
367        }
368    
369        /** An item representing a local variable.
370         */
371        class LocalItem extends Item {
372    
373            /** The variable's register.
374             */
375            int reg;
376    
377            /** The variable's type.
378             */
379            Type type;
380    
381            LocalItem(Type type, int reg) {
382                super(Code.typecode(type));
383                assert reg >= 0;
384                this.type = type;
385                this.reg = reg;
386            }
387    
388            Item load() {
389                if (reg <= 3)
390                    code.emitop0(iload_0 + Code.truncate(typecode) * 4 + reg);
391                else
392                    code.emitop1w(iload + Code.truncate(typecode), reg);
393                return stackItem[typecode];
394            }
395    
396            void store() {
397                if (reg <= 3)
398                    code.emitop0(istore_0 + Code.truncate(typecode) * 4 + reg);
399                else
400                    code.emitop1w(istore + Code.truncate(typecode), reg);
401                code.setDefined(reg);
402            }
403    
404            void incr(int x) {
405                if (typecode == INTcode && x >= -32768 && x <= 32767) {
406                    code.emitop1w(iinc, reg, x);
407                } else {
408                    load();
409                    if (x >= 0) {
410                        makeImmediateItem(syms.intType, x).load();
411                        code.emitop0(iadd);
412                    } else {
413                        makeImmediateItem(syms.intType, -x).load();
414                        code.emitop0(isub);
415                    }
416                    makeStackItem(syms.intType).coerce(typecode);
417                    store();
418                }
419            }
420    
421            public String toString() {
422                return "localItem(type=" + type + "; reg=" + reg + ")";
423            }
424        }
425    
426        /** An item representing a static variable or method.
427         */
428        class StaticItem extends Item {
429    
430            /** The represented symbol.
431             */
432            Symbol member;
433    
434            StaticItem(Symbol member) {
435                super(Code.typecode(member.erasure(types)));
436                this.member = member;
437            }
438    
439            Item load() {
440                code.emitop2(getstatic, pool.put(member));
441                return stackItem[typecode];
442            }
443    
444            void store() {
445                code.emitop2(putstatic, pool.put(member));
446            }
447    
448            Item invoke() {
449                MethodType mtype = (MethodType)member.erasure(types);
450                int rescode = Code.typecode(mtype.restype);
451                code.emitInvokestatic(pool.put(member), mtype);
452                return stackItem[rescode];
453            }
454    
455            public String toString() {
456                return "static(" + member + ")";
457            }
458        }
459    
460        /** An item representing an instance variable or method.
461         */
462        class MemberItem extends Item {
463    
464            /** The represented symbol.
465             */
466            Symbol member;
467    
468            /** Flag that determines whether or not access is virtual.
469             */
470            boolean nonvirtual;
471    
472            MemberItem(Symbol member, boolean nonvirtual) {
473                super(Code.typecode(member.erasure(types)));
474                this.member = member;
475                this.nonvirtual = nonvirtual;
476            }
477    
478            Item load() {
479                code.emitop2(getfield, pool.put(member));
480                return stackItem[typecode];
481            }
482    
483            void store() {
484                code.emitop2(putfield, pool.put(member));
485            }
486    
487            Item invoke() {
488                MethodType mtype = (MethodType)member.externalType(types);
489                int rescode = Code.typecode(mtype.restype);
490                if ((member.owner.flags() & Flags.INTERFACE) != 0) {
491                    code.emitInvokeinterface(pool.put(member), mtype);
492                } else if (nonvirtual) {
493                    code.emitInvokespecial(pool.put(member), mtype);
494                } else {
495                    code.emitInvokevirtual(pool.put(member), mtype);
496                }
497                return stackItem[rescode];
498            }
499    
500            void duplicate() {
501                stackItem[OBJECTcode].duplicate();
502            }
503    
504            void drop() {
505                stackItem[OBJECTcode].drop();
506            }
507    
508            void stash(int toscode) {
509                stackItem[OBJECTcode].stash(toscode);
510            }
511    
512            int width() {
513                return 1;
514            }
515    
516            public String toString() {
517                return "member(" + member + (nonvirtual ? " nonvirtual)" : ")");
518            }
519        }
520    
521        /** An item representing a literal.
522         */
523        class ImmediateItem extends Item {
524    
525            /** The literal's value.
526             */
527            Object value;
528    
529            ImmediateItem(Type type, Object value) {
530                super(Code.typecode(type));
531                this.value = value;
532            }
533    
534            private void ldc() {
535                int idx = pool.put(value);
536                if (typecode == LONGcode || typecode == DOUBLEcode) {
537                    code.emitop2(ldc2w, idx);
538                } else if (idx <= 255) {
539                    code.emitop1(ldc1, idx);
540                } else {
541                    code.emitop2(ldc2, idx);
542                }
543            }
544    
545            Item load() {
546                switch (typecode) {
547                case INTcode: case BYTEcode: case SHORTcode: case CHARcode:
548                    int ival = ((Number)value).intValue();
549                    if (-1 <= ival && ival <= 5)
550                        code.emitop0(iconst_0 + ival);
551                    else if (Byte.MIN_VALUE <= ival && ival <= Byte.MAX_VALUE)
552                        code.emitop1(bipush, ival);
553                    else if (Short.MIN_VALUE <= ival && ival <= Short.MAX_VALUE)
554                        code.emitop2(sipush, ival);
555                    else
556                        ldc();
557                    break;
558                case LONGcode:
559                    long lval = ((Number)value).longValue();
560                    if (lval == 0 || lval == 1)
561                        code.emitop0(lconst_0 + (int)lval);
562                    else
563                        ldc();
564                    break;
565                case FLOATcode:
566                    float fval = ((Number)value).floatValue();
567                    if (isPosZero(fval) || fval == 1.0 || fval == 2.0)
568                        code.emitop0(fconst_0 + (int)fval);
569                    else {
570                        ldc();
571                    }
572                    break;
573                case DOUBLEcode:
574                    double dval = ((Number)value).doubleValue();
575                    if (isPosZero(dval) || dval == 1.0)
576                        code.emitop0(dconst_0 + (int)dval);
577                    else
578                        ldc();
579                    break;
580                case OBJECTcode:
581                    ldc();
582                    break;
583                default:
584                    assert false;
585                }
586                return stackItem[typecode];
587            }
588            //where
589                /** Return true iff float number is positive 0.
590                 */
591                private boolean isPosZero(float x) {
592                    return x == 0.0f && 1.0f / x > 0.0f;
593                }
594                /** Return true iff double number is positive 0.
595                 */
596                private boolean isPosZero(double x) {
597                    return x == 0.0d && 1.0d / x > 0.0d;
598                }
599    
600            CondItem mkCond() {
601                int ival = ((Number)value).intValue();
602                return makeCondItem(ival != 0 ? goto_ : dontgoto);
603            }
604    
605            Item coerce(int targetcode) {
606                if (typecode == targetcode) {
607                    return this;
608                } else {
609                    switch (targetcode) {
610                    case INTcode:
611                        if (Code.truncate(typecode) == INTcode)
612                            return this;
613                        else
614                            return new ImmediateItem(
615                                syms.intType,
616                                ((Number)value).intValue());
617                    case LONGcode:
618                        return new ImmediateItem(
619                            syms.longType,
620                            ((Number)value).longValue());
621                    case FLOATcode:
622                        return new ImmediateItem(
623                            syms.floatType,
624                            ((Number)value).floatValue());
625                    case DOUBLEcode:
626                        return new ImmediateItem(
627                            syms.doubleType,
628                            ((Number)value).doubleValue());
629                    case BYTEcode:
630                        return new ImmediateItem(
631                            syms.byteType,
632                            (int)(byte)((Number)value).intValue());
633                    case CHARcode:
634                        return new ImmediateItem(
635                            syms.charType,
636                            (int)(char)((Number)value).intValue());
637                    case SHORTcode:
638                        return new ImmediateItem(
639                            syms.shortType,
640                            (int)(short)((Number)value).intValue());
641                    default:
642                        return super.coerce(targetcode);
643                    }
644                }
645            }
646    
647            public String toString() {
648                return "immediate(" + value + ")";
649            }
650        }
651    
652        /** An item representing an assignment expressions.
653         */
654        class AssignItem extends Item {
655    
656            /** The item representing the assignment's left hand side.
657             */
658            Item lhs;
659    
660            AssignItem(Item lhs) {
661                super(lhs.typecode);
662                this.lhs = lhs;
663            }
664    
665            Item load() {
666                lhs.stash(typecode);
667                lhs.store();
668                return stackItem[typecode];
669            }
670    
671            void duplicate() {
672                load().duplicate();
673            }
674    
675            void drop() {
676                lhs.store();
677            }
678    
679            void stash(int toscode) {
680                assert false;
681            }
682    
683            int width() {
684                return lhs.width() + Code.width(typecode);
685            }
686    
687            public String toString() {
688                return "assign(lhs = " + lhs + ")";
689            }
690        }
691    
692        /** An item representing a conditional or unconditional jump.
693         */
694        class CondItem extends Item {
695    
696            /** A chain encomassing all jumps that can be taken
697             *  if the condition evaluates to true.
698             */
699            Chain trueJumps;
700    
701            /** A chain encomassing all jumps that can be taken
702             *  if the condition evaluates to false.
703             */
704            Chain falseJumps;
705    
706            /** The jump's opcode.
707             */
708            int opcode;
709    
710            /*
711             *  An abstract syntax tree of this item. It is needed
712             *  for branch entries in 'CharacterRangeTable' attribute.
713             */
714            JCTree tree;
715    
716            CondItem(int opcode, Chain truejumps, Chain falsejumps) {
717                super(BYTEcode);
718                this.opcode = opcode;
719                this.trueJumps = truejumps;
720                this.falseJumps = falsejumps;
721            }
722    
723            Item load() {
724                Chain trueChain = null;
725                Chain falseChain = jumpFalse();
726                if (!isFalse()) {
727                    code.resolve(trueJumps);
728                    code.emitop0(iconst_1);
729                    trueChain = code.branch(goto_);
730                }
731                if (falseChain != null) {
732                    code.resolve(falseChain);
733                    code.emitop0(iconst_0);
734                }
735                code.resolve(trueChain);
736                return stackItem[typecode];
737            }
738    
739            void duplicate() {
740                load().duplicate();
741            }
742    
743            void drop() {
744                load().drop();
745            }
746    
747            void stash(int toscode) {
748                assert false;
749            }
750    
751            CondItem mkCond() {
752                return this;
753            }
754    
755            Chain jumpTrue() {
756                if (tree == null) return code.mergeChains(trueJumps, code.branch(opcode));
757                // we should proceed further in -Xjcov mode only
758                int startpc = code.curPc();
759                Chain c = code.mergeChains(trueJumps, code.branch(opcode));
760                code.crt.put(tree, CRTable.CRT_BRANCH_TRUE, startpc, code.curPc());
761                return c;
762            }
763    
764            Chain jumpFalse() {
765                if (tree == null) return code.mergeChains(falseJumps, code.branch(code.negate(opcode)));
766                // we should proceed further in -Xjcov mode only
767                int startpc = code.curPc();
768                Chain c = code.mergeChains(falseJumps, code.branch(code.negate(opcode)));
769                code.crt.put(tree, CRTable.CRT_BRANCH_FALSE, startpc, code.curPc());
770                return c;
771            }
772    
773            CondItem negate() {
774                CondItem c = new CondItem(code.negate(opcode), falseJumps, trueJumps);
775                c.tree = tree;
776                return c;
777            }
778    
779            int width() {
780                // a CondItem doesn't have a size on the stack per se.
781                throw new AssertionError();
782            }
783    
784            boolean isTrue() {
785                return falseJumps == null && opcode == goto_;
786            }
787    
788            boolean isFalse() {
789                return trueJumps == null && opcode == dontgoto;
790            }
791    
792            public String toString() {
793                return "cond(" + Code.mnem(opcode) + ")";
794            }
795        }
796    }