1 /*
2 * Copyright (c) 1999, 2022, 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.externalType(types); // static factories
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 && typecode != CHARcode)
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 }
--- EOF ---