1 /*
  2  * Copyright (c) 1999, 2019, 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 
 26 package com.sun.tools.javac.jvm;
 27 
 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.jvm.PoolConstant.LoadableConstant;
 33 import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant.BasicConstant;
 34 import com.sun.tools.javac.tree.JCTree;
 35 import com.sun.tools.javac.util.Assert;
 36 
 37 import static com.sun.tools.javac.jvm.ByteCodes.*;
 38 
 39 /** A helper class for code generation. Items are objects
 40  *  that stand for addressable entities in the bytecode. Each item
 41  *  supports a fixed protocol for loading the item on the stack, storing
 42  *  into it, converting it into a jump condition, and several others.
 43  *  There are many individual forms of items, such as local, static,
 44  *  indexed, or instance variables, values on the top of stack, the
 45  *  special values this or super, etc. Individual items are represented as
 46  *  inner classes in class Items.
 47  *
 48  *  <p><b>This is NOT part of any supported API.
 49  *  If you write code that depends on this, you do so at your own risk.
 50  *  This code and its internal interfaces are subject to change or
 51  *  deletion without notice.</b>
 52  */
 53 public class Items {
 54 
 55     /** The current constant pool writer.
 56      */
 57     PoolWriter poolWriter;
 58 
 59     /** The current code buffer.
 60      */
 61     Code code;
 62 
 63     /** The current symbol table.
 64      */
 65     Symtab syms;
 66 
 67     /** Type utilities. */
 68     Types types;
 69 
 70     /** Items that exist only once (flyweight pattern).
 71      */
 72     private final Item voidItem;
 73     private final Item thisItem;
 74     private final Item superItem;
 75     private final Item[] stackItem = new Item[TypeCodeCount];
 76 
 77     public Items(PoolWriter poolWriter, Code code, Symtab syms, Types types) {
 78         this.code = code;
 79         this.poolWriter = poolWriter;
 80         this.types = types;
 81         voidItem = new Item(VOIDcode) {
 82                 public String toString() { return "void"; }
 83             };
 84         thisItem = new SelfItem(false);
 85         superItem = new SelfItem(true);
 86         for (int i = 0; i < VOIDcode; i++) stackItem[i] = new StackItem(i);
 87         stackItem[VOIDcode] = voidItem;
 88         this.syms = syms;
 89     }
 90 
 91     /** Make a void item
 92      */
 93     Item makeVoidItem() {
 94         return voidItem;
 95     }
 96     /** Make an item representing `this'.
 97      */
 98     Item makeThisItem() {
 99         return thisItem;
100     }
101 
102     /** Make an item representing `super'.
103      */
104     Item makeSuperItem() {
105         return superItem;
106     }
107 
108     /** Make an item representing a value on stack.
109      *  @param type    The value's type.
110      */
111     Item makeStackItem(Type type) {
112         return stackItem[Code.typecode(type)];
113     }
114 
115     /** Make an item representing a dynamically invoked method.
116      *  @param member   The represented symbol.
117      */
118     Item makeDynamicItem(Symbol member) {
119         return new DynamicItem(member);
120     }
121 
122     /** Make an item representing an indexed expression.
123      *  @param type    The expression's type.
124      */
125     Item makeIndexedItem(Type type) {
126         return new IndexedItem(type);
127     }
128 
129     /** Make an item representing a local variable.
130      *  @param v    The represented variable.
131      */
132     LocalItem makeLocalItem(VarSymbol v) {
133         return new LocalItem(v.erasure(types), v.adr);
134     }
135 
136     /** Make an item representing a local anonymous variable.
137      *  @param type  The represented variable's type.
138      *  @param reg   The represented variable's register.
139      */
140     private LocalItem makeLocalItem(Type type, int reg) {
141         return new LocalItem(type, reg);
142     }
143 
144     /** Make an item representing a static variable or method.
145      *  @param member   The represented symbol.
146      */
147     Item makeStaticItem(Symbol member) {
148         return new StaticItem(member);
149     }
150 
151     /** Make an item representing an instance variable or method.
152      *  @param member       The represented symbol.
153      *  @param nonvirtual   Is the reference not virtual? (true for constructors
154      *                      and private members).
155      */
156     Item makeMemberItem(Symbol member, boolean nonvirtual) {
157         return new MemberItem(member, nonvirtual);
158     }
159 
160     /** Make an item representing a literal.
161      *  @param type     The literal's type.
162      *  @param value    The literal's value.
163      */
164     Item makeImmediateItem(Type type, Object value) {
165         return new ImmediateItem(type, value);
166     }
167 
168     /** Make an item representing an assignment expression.
169      *  @param lhs      The item representing the assignment's left hand side.
170      */
171     Item makeAssignItem(Item lhs) {
172         return new AssignItem(lhs);
173     }
174 
175     /** Make an item representing a conditional or unconditional jump.
176      *  @param opcode      The jump's opcode.
177      *  @param trueJumps   A chain encompassing all jumps that can be taken
178      *                     if the condition evaluates to true.
179      *  @param falseJumps  A chain encompassing all jumps that can be taken
180      *                     if the condition evaluates to false.
181      */
182     CondItem makeCondItem(int opcode, Chain trueJumps, Chain falseJumps) {
183         return new CondItem(opcode, trueJumps, falseJumps);
184     }
185 
186     /** Make an item representing a conditional or unconditional jump.
187      *  @param opcode      The jump's opcode.
188      */
189     CondItem makeCondItem(int opcode) {
190         return makeCondItem(opcode, null, null);
191     }
192 
193     /** The base class of all items, which implements default behavior.
194      */
195     abstract class Item {
196 
197         /** The type code of values represented by this item.
198          */
199         int typecode;
200 
201         Item(int typecode) {
202             this.typecode = typecode;
203         }
204 
205         /** Generate code to load this item onto stack.
206          */
207         Item load() {
208             throw new AssertionError();
209         }
210 
211         /** Generate code to store top of stack into this item.
212          */
213         void store() {
214             throw new AssertionError("store unsupported: " + this);
215         }
216 
217         /** Generate code to invoke method represented by this item.
218          */
219         Item invoke() {
220             throw new AssertionError(this);
221         }
222 
223         /** Generate code to use this item twice.
224          */
225         void duplicate() {}
226 
227         /** Generate code to avoid having to use this item.
228          */
229         void drop() {}
230 
231         /** Generate code to stash a copy of top of stack - of typecode toscode -
232          *  under this item.
233          */
234         void stash(int toscode) {
235             stackItem[toscode].duplicate();
236         }
237 
238         /** Generate code to turn item into a testable condition.
239          */
240         CondItem mkCond() {
241             load();
242             return makeCondItem(ifne);
243         }
244 
245         /** Generate code to coerce item to given type code.
246          *  @param targetcode    The type code to coerce to.
247          */
248         Item coerce(int targetcode) {
249             if (typecode == targetcode)
250                 return this;
251             else {
252                 load();
253                 int typecode1 = Code.truncate(typecode);
254                 int targetcode1 = Code.truncate(targetcode);
255                 if (typecode1 != targetcode1) {
256                     int offset = targetcode1 > typecode1 ? targetcode1 - 1
257                         : targetcode1;
258                     code.emitop0(i2l + typecode1 * 3 + offset);
259                 }
260                 if (targetcode != targetcode1) {
261                     code.emitop0(int2byte + targetcode - BYTEcode);
262                 }
263                 return stackItem[targetcode];
264             }
265         }
266 
267         /** Generate code to coerce item to given type.
268          *  @param targettype    The type to coerce to.
269          */
270         Item coerce(Type targettype) {
271             return coerce(Code.typecode(targettype));
272         }
273 
274         /** Return the width of this item on stack as a number of words.
275          */
276         int width() {
277             return 0;
278         }
279 
280         public abstract String toString();
281     }
282 
283     /** An item representing a value on stack.
284      */
285     class StackItem extends Item {
286 
287         StackItem(int typecode) {
288             super(typecode);
289         }
290 
291         Item load() {
292             return this;
293         }
294 
295         void duplicate() {
296             code.emitop0(width() == 2 ? dup2 : dup);
297         }
298 
299         void drop() {
300             code.emitop0(width() == 2 ? pop2 : pop);
301         }
302 
303         void stash(int toscode) {
304             code.emitop0(
305                 (width() == 2 ? dup_x2 : dup_x1) + 3 * (Code.width(toscode) - 1));
306         }
307 
308         int width() {
309             return Code.width(typecode);
310         }
311 
312         public String toString() {
313             return "stack(" + typecodeNames[typecode] + ")";
314         }
315     }
316 
317     /** An item representing an indexed expression.
318      */
319     class IndexedItem extends Item {
320 
321         IndexedItem(Type type) {
322             super(Code.typecode(type));
323         }
324 
325         Item load() {
326             code.emitop0(iaload + typecode);
327             return stackItem[typecode];
328         }
329 
330         void store() {
331             code.emitop0(iastore + typecode);
332         }
333 
334         void duplicate() {
335             code.emitop0(dup2);
336         }
337 
338         void drop() {
339             code.emitop0(pop2);
340         }
341 
342         void stash(int toscode) {
343             code.emitop0(dup_x2 + 3 * (Code.width(toscode) - 1));
344         }
345 
346         int width() {
347             return 2;
348         }
349 
350         public String toString() {
351             return "indexed(" + ByteCodes.typecodeNames[typecode] + ")";
352         }
353     }
354 
355     /** An item representing `this' or `super'.
356      */
357     class SelfItem extends Item {
358 
359         /** Flag which determines whether this item represents `this' or `super'.
360          */
361         boolean isSuper;
362 
363         SelfItem(boolean isSuper) {
364             super(OBJECTcode);
365             this.isSuper = isSuper;
366         }
367 
368         Item load() {
369             code.emitop0(aload_0);
370             return stackItem[typecode];
371         }
372 
373         public String toString() {
374             return isSuper ? "super" : "this";
375         }
376     }
377 
378     /** An item representing a local variable.
379      */
380     class LocalItem extends Item {
381 
382         /** The variable's register.
383          */
384         int reg;
385 
386         /** The variable's type.
387          */
388         Type type;
389 
390         LocalItem(Type type, int reg) {
391             super(Code.typecode(type));
392             Assert.check(reg >= 0);
393             this.type = type;
394             this.reg = reg;
395         }
396 
397         Item load() {
398             if (reg <= 3)
399                 code.emitop0(iload_0 + Code.truncate(typecode) * 4 + reg);
400             else
401                 code.emitop1w(iload + Code.truncate(typecode), reg);
402             return stackItem[typecode];
403         }
404 
405         void store() {
406             if (reg <= 3)
407                 code.emitop0(istore_0 + Code.truncate(typecode) * 4 + reg);
408             else
409                 code.emitop1w(istore + Code.truncate(typecode), reg);
410             code.setDefined(reg);
411         }
412 
413         void incr(int x) {
414             if (typecode == INTcode && x >= -32768 && x <= 32767) {
415                 code.emitop1w(iinc, reg, x);
416             } else {
417                 load();
418                 if (x >= 0) {
419                     makeImmediateItem(syms.intType, x).load();
420                     code.emitop0(iadd);
421                 } else {
422                     makeImmediateItem(syms.intType, -x).load();
423                     code.emitop0(isub);
424                 }
425                 makeStackItem(syms.intType).coerce(typecode);
426                 store();
427             }
428         }
429 
430         public String toString() {
431             return "localItem(type=" + type + "; reg=" + reg + ")";
432         }
433     }
434 
435     /** An item representing a static variable or method.
436      */
437     class StaticItem extends Item {
438 
439         /** The represented symbol.
440          */
441         Symbol member;
442 
443         StaticItem(Symbol member) {
444             super(Code.typecode(member.erasure(types)));
445             this.member = member;
446         }
447 
448         Item load() {
449             code.emitop2(getstatic, member, PoolWriter::putMember);
450             return stackItem[typecode];
451         }
452 
453         void store() {
454             code.emitop2(putstatic, member, PoolWriter::putMember);
455         }
456 
457         Item invoke() {
458             MethodType mtype = (MethodType)member.erasure(types);
459             int rescode = Code.typecode(mtype.restype);
460             code.emitInvokestatic(member, mtype);
461             return stackItem[rescode];
462         }
463 
464         public String toString() {
465             return "static(" + member + ")";
466         }
467     }
468 
469     /** An item representing a dynamic call site.
470      */
471     class DynamicItem extends StaticItem {
472         DynamicItem(Symbol member) {
473             super(member);
474         }
475 
476         Item load() {
477             Assert.check(member.kind == Kinds.Kind.VAR);
478             Type type = member.erasure(types);
479             int rescode = Code.typecode(type);
480             code.emitLdc((DynamicVarSymbol)member);
481             return stackItem[rescode];
482         }
483 
484         void store() { Assert.error("this method shouldn't be invoked"); }
485 
486         Item invoke() {
487             Assert.check(member.kind == Kinds.Kind.MTH);
488             MethodType mtype = (MethodType)member.erasure(types);
489             int rescode = Code.typecode(mtype.restype);
490             code.emitInvokedynamic((DynamicMethodSymbol)member, mtype);
491             return stackItem[rescode];
492         }
493 
494         public String toString() {
495             return "dynamic(" + member + ")";
496         }
497     }
498 
499     /** An item representing an instance variable or method.
500      */
501     class MemberItem extends Item {
502 
503         /** The represented symbol.
504          */
505         Symbol member;
506 
507         /** Flag that determines whether or not access is virtual.
508          */
509         boolean nonvirtual;
510 
511         MemberItem(Symbol member, boolean nonvirtual) {
512             super(Code.typecode(member.erasure(types)));
513             this.member = member;
514             this.nonvirtual = nonvirtual;
515         }
516 
517         Item load() {
518             code.emitop2(getfield, member, PoolWriter::putMember);
519             return stackItem[typecode];
520         }
521 
522         void store() {
523             code.emitop2(putfield, member, PoolWriter::putMember);
524         }
525 
526         Item invoke() {
527             MethodType mtype = (MethodType)member.externalType(types);
528             int rescode = Code.typecode(mtype.restype);
529             if ((member.owner.flags() & Flags.INTERFACE) != 0 && !nonvirtual) {
530                 code.emitInvokeinterface(member, mtype);
531             } else if (nonvirtual) {
532                 code.emitInvokespecial(member, mtype);
533             } else {
534                 code.emitInvokevirtual(member, mtype);
535             }
536             return stackItem[rescode];
537         }
538 
539         void duplicate() {
540             stackItem[OBJECTcode].duplicate();
541         }
542 
543         void drop() {
544             stackItem[OBJECTcode].drop();
545         }
546 
547         void stash(int toscode) {
548             stackItem[OBJECTcode].stash(toscode);
549         }
550 
551         int width() {
552             return 1;
553         }
554 
555         public String toString() {
556             return "member(" + member + (nonvirtual ? " nonvirtual)" : ")");
557         }
558     }
559 
560     /** An item representing a literal.
561      */
562     class ImmediateItem extends Item {
563 
564         /** The literal's value.
565          */
566         final LoadableConstant value;
567 
568         ImmediateItem(Type type, Object value) {
569             super(Code.typecode(type));
570             switch (typecode) {
571                 case BYTEcode:
572                 case SHORTcode:
573                 case CHARcode:
574                 case INTcode:
575                     this.value = LoadableConstant.Int((int)value);
576                     break;
577                 case LONGcode:
578                     this.value = LoadableConstant.Long((long)value);
579                     break;
580                 case FLOATcode:
581                     this.value = LoadableConstant.Float((float)value);
582                     break;
583                 case DOUBLEcode:
584                     this.value = LoadableConstant.Double((double)value);
585                     break;
586                 case OBJECTcode:
587                     this.value = LoadableConstant.String((String)value);
588                     break;
589                 default:
590                     throw new UnsupportedOperationException("unsupported tag: " + typecode);
591             }
592         }
593 
594         private void ldc() {
595             if (typecode == LONGcode || typecode == DOUBLEcode) {
596                 code.emitop2(ldc2w, value, PoolWriter::putConstant);
597             } else {
598                 code.emitLdc(value);
599             }
600         }
601 
602         private Number numericValue() {
603             return (Number)((BasicConstant)value).data;
604         }
605 
606         Item load() {
607             switch (typecode) {
608             case INTcode: case BYTEcode: case SHORTcode: case CHARcode:
609                 int ival = numericValue().intValue();
610                 if (-1 <= ival && ival <= 5)
611                     code.emitop0(iconst_0 + ival);
612                 else if (Byte.MIN_VALUE <= ival && ival <= Byte.MAX_VALUE)
613                     code.emitop1(bipush, ival);
614                 else if (Short.MIN_VALUE <= ival && ival <= Short.MAX_VALUE)
615                     code.emitop2(sipush, ival);
616                 else
617                     ldc();
618                 break;
619             case LONGcode:
620                 long lval = numericValue().longValue();
621                 if (lval == 0 || lval == 1)
622                     code.emitop0(lconst_0 + (int)lval);
623                 else
624                     ldc();
625                 break;
626             case FLOATcode:
627                 float fval = numericValue().floatValue();
628                 if (isPosZero(fval) || fval == 1.0 || fval == 2.0)
629                     code.emitop0(fconst_0 + (int)fval);
630                 else {
631                     ldc();
632                 }
633                 break;
634             case DOUBLEcode:
635                 double dval = numericValue().doubleValue();
636                 if (isPosZero(dval) || dval == 1.0)
637                     code.emitop0(dconst_0 + (int)dval);
638                 else
639                     ldc();
640                 break;
641             case OBJECTcode:
642                 ldc();
643                 break;
644             default:
645                 Assert.error();
646             }
647             return stackItem[typecode];
648         }
649         //where
650             /** Return true iff float number is positive 0.
651              */
652             private boolean isPosZero(float x) {
653                 return x == 0.0f && 1.0f / x > 0.0f;
654             }
655             /** Return true iff double number is positive 0.
656              */
657             private boolean isPosZero(double x) {
658                 return x == 0.0d && 1.0d / x > 0.0d;
659             }
660 
661         CondItem mkCond() {
662             int ival = numericValue().intValue();
663             return makeCondItem(ival != 0 ? goto_ : dontgoto);
664         }
665 
666         Item coerce(int targetcode) {
667             if (typecode == targetcode) {
668                 return this;
669             } else {
670                 switch (targetcode) {
671                 case INTcode:
672                     if (Code.truncate(typecode) == INTcode)
673                         return this;
674                     else
675                         return new ImmediateItem(
676                             syms.intType,
677                             numericValue().intValue());
678                 case LONGcode:
679                     return new ImmediateItem(
680                         syms.longType,
681                             numericValue().longValue());
682                 case FLOATcode:
683                     return new ImmediateItem(
684                         syms.floatType,
685                         numericValue().floatValue());
686                 case DOUBLEcode:
687                     return new ImmediateItem(
688                         syms.doubleType,
689                         numericValue().doubleValue());
690                 case BYTEcode:
691                     return new ImmediateItem(
692                         syms.byteType,
693                         (int)(byte)numericValue().intValue());
694                 case CHARcode:
695                     return new ImmediateItem(
696                         syms.charType,
697                         (int)(char)numericValue().intValue());
698                 case SHORTcode:
699                     return new ImmediateItem(
700                         syms.shortType,
701                         (int)(short)numericValue().intValue());
702                 default:
703                     return super.coerce(targetcode);
704                 }
705             }
706         }
707 
708         public String toString() {
709             return "immediate(" + value + ")";
710         }
711     }
712 
713     /** An item representing an assignment expressions.
714      */
715     class AssignItem extends Item {
716 
717         /** The item representing the assignment's left hand side.
718          */
719         Item lhs;
720 
721         AssignItem(Item lhs) {
722             super(lhs.typecode);
723             this.lhs = lhs;
724         }
725 
726         Item load() {
727             lhs.stash(typecode);
728             lhs.store();
729             return stackItem[typecode];
730         }
731 
732         void duplicate() {
733             load().duplicate();
734         }
735 
736         void drop() {
737             lhs.store();
738         }
739 
740         void stash(int toscode) {
741             Assert.error();
742         }
743 
744         int width() {
745             return lhs.width() + Code.width(typecode);
746         }
747 
748         public String toString() {
749             return "assign(lhs = " + lhs + ")";
750         }
751     }
752 
753     /** An item representing a conditional or unconditional jump.
754      */
755     class CondItem extends Item {
756 
757         /** A chain encompassing all jumps that can be taken
758          *  if the condition evaluates to true.
759          */
760         Chain trueJumps;
761 
762         /** A chain encompassing all jumps that can be taken
763          *  if the condition evaluates to false.
764          */
765         Chain falseJumps;
766 
767         /** The jump's opcode.
768          */
769         int opcode;
770 
771         /*
772          *  An abstract syntax tree of this item. It is needed
773          *  for branch entries in 'CharacterRangeTable' attribute.
774          */
775         JCTree tree;
776 
777         CondItem(int opcode, Chain truejumps, Chain falsejumps) {
778             super(BYTEcode);
779             this.opcode = opcode;
780             this.trueJumps = truejumps;
781             this.falseJumps = falsejumps;
782         }
783 
784         Item load() {
785             Chain trueChain = null;
786             Chain falseChain = jumpFalse();
787             if (!isFalse()) {
788                 code.resolve(trueJumps);
789                 code.emitop0(iconst_1);
790                 trueChain = code.branch(goto_);
791             }
792             if (falseChain != null) {
793                 code.resolve(falseChain);
794                 code.emitop0(iconst_0);
795             }
796             code.resolve(trueChain);
797             return stackItem[typecode];
798         }
799 
800         void duplicate() {
801             load().duplicate();
802         }
803 
804         void drop() {
805             load().drop();
806         }
807 
808         void stash(int toscode) {
809             Assert.error();
810         }
811 
812         CondItem mkCond() {
813             return this;
814         }
815 
816         Chain jumpTrue() {
817             if (tree == null) return Code.mergeChains(trueJumps, code.branch(opcode));
818             // we should proceed further in -Xjcov mode only
819             int startpc = code.curCP();
820             Chain c = Code.mergeChains(trueJumps, code.branch(opcode));
821             code.crt.put(tree, CRTable.CRT_BRANCH_TRUE, startpc, code.curCP());
822             return c;
823         }
824 
825         Chain jumpFalse() {
826             if (tree == null) return Code.mergeChains(falseJumps, code.branch(Code.negate(opcode)));
827             // we should proceed further in -Xjcov mode only
828             int startpc = code.curCP();
829             Chain c = Code.mergeChains(falseJumps, code.branch(Code.negate(opcode)));
830             code.crt.put(tree, CRTable.CRT_BRANCH_FALSE, startpc, code.curCP());
831             return c;
832         }
833 
834         CondItem negate() {
835             CondItem c = new CondItem(Code.negate(opcode), falseJumps, trueJumps);
836             c.tree = tree;
837             return c;
838         }
839 
840         int width() {
841             // a CondItem doesn't have a size on the stack per se.
842             throw new AssertionError();
843         }
844 
845         boolean isTrue() {
846             return falseJumps == null && opcode == goto_;
847         }
848 
849         boolean isFalse() {
850             return trueJumps == null && opcode == dontgoto;
851         }
852 
853         public String toString() {
854             return "cond(" + Code.mnem(opcode) + ")";
855         }
856     }
857 }