Items.java revision 2571:10fc81ac75b4
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 */
25
26package com.sun.tools.javac.jvm;
27
28import com.sun.tools.javac.code.*;
29import com.sun.tools.javac.code.Symbol.*;
30import com.sun.tools.javac.code.Type.*;
31import com.sun.tools.javac.jvm.Code.*;
32import com.sun.tools.javac.tree.JCTree;
33import com.sun.tools.javac.util.Assert;
34
35import static com.sun.tools.javac.jvm.ByteCodes.*;
36
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 */
51public class Items {
52
53    /** The current constant pool.
54     */
55    Pool pool;
56
57    /** The current code buffer.
58     */
59    Code code;
60
61    /** The current symbol table.
62     */
63    Symtab syms;
64
65    /** Type utilities. */
66    Types types;
67
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];
74
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    }
88
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    }
99
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 a dynamically invoked method.
114     *  @param member   The represented symbol.
115     */
116    Item makeDynamicItem(Symbol member) {
117        return new DynamicItem(member);
118    }
119
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    }
126
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    }
133
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    }
141
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    }
148
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    }
157
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    }
165
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    }
172
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    }
183
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    }
190
191    /** The base class of all items, which implements default behavior.
192     */
193    abstract class Item {
194
195        /** The type code of values represented by this item.
196         */
197        int typecode;
198
199        Item(int typecode) {
200            this.typecode = typecode;
201        }
202
203        /** Generate code to load this item onto stack.
204         */
205        Item load() {
206            throw new AssertionError();
207        }
208
209        /** Generate code to store top of stack into this item.
210         */
211        void store() {
212            throw new AssertionError("store unsupported: " + this);
213        }
214
215        /** Generate code to invoke method represented by this item.
216         */
217        Item invoke() {
218            throw new AssertionError(this);
219        }
220
221        /** Generate code to use this item twice.
222         */
223        void duplicate() {}
224
225        /** Generate code to avoid having to use this item.
226         */
227        void drop() {}
228
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        }
235
236        /** Generate code to turn item into a testable condition.
237         */
238        CondItem mkCond() {
239            load();
240            return makeCondItem(ifne);
241        }
242
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        }
264
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        }
271
272        /** Return the width of this item on stack as a number of words.
273         */
274        int width() {
275            return 0;
276        }
277
278        public abstract String toString();
279    }
280
281    /** An item representing a value on stack.
282     */
283    class StackItem extends Item {
284
285        StackItem(int typecode) {
286            super(typecode);
287        }
288
289        Item load() {
290            return this;
291        }
292
293        void duplicate() {
294            code.emitop0(width() == 2 ? dup2 : dup);
295        }
296
297        void drop() {
298            code.emitop0(width() == 2 ? pop2 : pop);
299        }
300
301        void stash(int toscode) {
302            code.emitop0(
303                (width() == 2 ? dup_x2 : dup_x1) + 3 * (Code.width(toscode) - 1));
304        }
305
306        int width() {
307            return Code.width(typecode);
308        }
309
310        public String toString() {
311            return "stack(" + typecodeNames[typecode] + ")";
312        }
313    }
314
315    /** An item representing an indexed expression.
316     */
317    class IndexedItem extends Item {
318
319        IndexedItem(Type type) {
320            super(Code.typecode(type));
321        }
322
323        Item load() {
324            code.emitop0(iaload + typecode);
325            return stackItem[typecode];
326        }
327
328        void store() {
329            code.emitop0(iastore + typecode);
330        }
331
332        void duplicate() {
333            code.emitop0(dup2);
334        }
335
336        void drop() {
337            code.emitop0(pop2);
338        }
339
340        void stash(int toscode) {
341            code.emitop0(dup_x2 + 3 * (Code.width(toscode) - 1));
342        }
343
344        int width() {
345            return 2;
346        }
347
348        public String toString() {
349            return "indexed(" + ByteCodes.typecodeNames[typecode] + ")";
350        }
351    }
352
353    /** An item representing `this' or `super'.
354     */
355    class SelfItem extends Item {
356
357        /** Flag which determines whether this item represents `this' or `super'.
358         */
359        boolean isSuper;
360
361        SelfItem(boolean isSuper) {
362            super(OBJECTcode);
363            this.isSuper = isSuper;
364        }
365
366        Item load() {
367            code.emitop0(aload_0);
368            return stackItem[typecode];
369        }
370
371        public String toString() {
372            return isSuper ? "super" : "this";
373        }
374    }
375
376    /** An item representing a local variable.
377     */
378    class LocalItem extends Item {
379
380        /** The variable's register.
381         */
382        int reg;
383
384        /** The variable's type.
385         */
386        Type type;
387
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        }
394
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        }
402
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        }
410
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        }
427
428        public String toString() {
429            return "localItem(type=" + type + "; reg=" + reg + ")";
430        }
431    }
432
433    /** An item representing a static variable or method.
434     */
435    class StaticItem extends Item {
436
437        /** The represented symbol.
438         */
439        Symbol member;
440
441        StaticItem(Symbol member) {
442            super(Code.typecode(member.erasure(types)));
443            this.member = member;
444        }
445
446        Item load() {
447            code.emitop2(getstatic, pool.put(member));
448            return stackItem[typecode];
449        }
450
451        void store() {
452            code.emitop2(putstatic, pool.put(member));
453        }
454
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        }
461
462        public String toString() {
463            return "static(" + member + ")";
464        }
465    }
466
467    /** An item representing a dynamic call site.
468     */
469    class DynamicItem extends StaticItem {
470        DynamicItem(Symbol member) {
471            super(member);
472        }
473
474        Item load() {
475            assert false;
476            return null;
477        }
478
479        void store() {
480            assert false;
481        }
482
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        }
490
491        public String toString() {
492            return "dynamic(" + member + ")";
493        }
494    }
495
496    /** An item representing an instance variable or method.
497     */
498    class MemberItem extends Item {
499
500        /** The represented symbol.
501         */
502        Symbol member;
503
504        /** Flag that determines whether or not access is virtual.
505         */
506        boolean nonvirtual;
507
508        MemberItem(Symbol member, boolean nonvirtual) {
509            super(Code.typecode(member.erasure(types)));
510            this.member = member;
511            this.nonvirtual = nonvirtual;
512        }
513
514        Item load() {
515            code.emitop2(getfield, pool.put(member));
516            return stackItem[typecode];
517        }
518
519        void store() {
520            code.emitop2(putfield, pool.put(member));
521        }
522
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        }
535
536        void duplicate() {
537            stackItem[OBJECTcode].duplicate();
538        }
539
540        void drop() {
541            stackItem[OBJECTcode].drop();
542        }
543
544        void stash(int toscode) {
545            stackItem[OBJECTcode].stash(toscode);
546        }
547
548        int width() {
549            return 1;
550        }
551
552        public String toString() {
553            return "member(" + member + (nonvirtual ? " nonvirtual)" : ")");
554        }
555    }
556
557    /** An item representing a literal.
558     */
559    class ImmediateItem extends Item {
560
561        /** The literal's value.
562         */
563        Object value;
564
565        ImmediateItem(Type type, Object value) {
566            super(Code.typecode(type));
567            this.value = value;
568        }
569
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        }
578
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            }
633
634        CondItem mkCond() {
635            int ival = ((Number)value).intValue();
636            return makeCondItem(ival != 0 ? goto_ : dontgoto);
637        }
638
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        }
680
681        public String toString() {
682            return "immediate(" + value + ")";
683        }
684    }
685
686    /** An item representing an assignment expressions.
687     */
688    class AssignItem extends Item {
689
690        /** The item representing the assignment's left hand side.
691         */
692        Item lhs;
693
694        AssignItem(Item lhs) {
695            super(lhs.typecode);
696            this.lhs = lhs;
697        }
698
699        Item load() {
700            lhs.stash(typecode);
701            lhs.store();
702            return stackItem[typecode];
703        }
704
705        void duplicate() {
706            load().duplicate();
707        }
708
709        void drop() {
710            lhs.store();
711        }
712
713        void stash(int toscode) {
714            Assert.error();
715        }
716
717        int width() {
718            return lhs.width() + Code.width(typecode);
719        }
720
721        public String toString() {
722            return "assign(lhs = " + lhs + ")";
723        }
724    }
725
726    /** An item representing a conditional or unconditional jump.
727     */
728    class CondItem extends Item {
729
730        /** A chain encomassing all jumps that can be taken
731         *  if the condition evaluates to true.
732         */
733        Chain trueJumps;
734
735        /** A chain encomassing all jumps that can be taken
736         *  if the condition evaluates to false.
737         */
738        Chain falseJumps;
739
740        /** The jump's opcode.
741         */
742        int opcode;
743
744        /*
745         *  An abstract syntax tree of this item. It is needed
746         *  for branch entries in 'CharacterRangeTable' attribute.
747         */
748        JCTree tree;
749
750        CondItem(int opcode, Chain truejumps, Chain falsejumps) {
751            super(BYTEcode);
752            this.opcode = opcode;
753            this.trueJumps = truejumps;
754            this.falseJumps = falsejumps;
755        }
756
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        }
772
773        void duplicate() {
774            load().duplicate();
775        }
776
777        void drop() {
778            load().drop();
779        }
780
781        void stash(int toscode) {
782            Assert.error();
783        }
784
785        CondItem mkCond() {
786            return this;
787        }
788
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.curCP();
793            Chain c = Code.mergeChains(trueJumps, code.branch(opcode));
794            code.crt.put(tree, CRTable.CRT_BRANCH_TRUE, startpc, code.curCP());
795            return c;
796        }
797
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.curCP();
802            Chain c = Code.mergeChains(falseJumps, code.branch(Code.negate(opcode)));
803            code.crt.put(tree, CRTable.CRT_BRANCH_FALSE, startpc, code.curCP());
804            return c;
805        }
806
807        CondItem negate() {
808            CondItem c = new CondItem(Code.negate(opcode), falseJumps, trueJumps);
809            c.tree = tree;
810            return c;
811        }
812
813        int width() {
814            // a CondItem doesn't have a size on the stack per se.
815            throw new AssertionError();
816        }
817
818        boolean isTrue() {
819            return falseJumps == null && opcode == goto_;
820        }
821
822        boolean isFalse() {
823            return trueJumps == null && opcode == dontgoto;
824        }
825
826        public String toString() {
827            return "cond(" + Code.mnem(opcode) + ")";
828        }
829    }
830}
831