Fri, 03 May 2013 15:08:47 -0700
8000407: remove @GenerateNativeHeader
Reviewed-by: vromero, darcy
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 */
26 package com.sun.tools.javac.jvm;
28 import com.sun.tools.javac.code.*;
29 import com.sun.tools.javac.code.Symbol.*;
30 import com.sun.tools.javac.code.Type.*;
31 import com.sun.tools.javac.jvm.Code.*;
32 import com.sun.tools.javac.tree.JCTree;
33 import com.sun.tools.javac.util.Assert;
35 import static com.sun.tools.javac.jvm.ByteCodes.*;
37 /** A helper class for code generation. Items are objects
38 * that stand for addressable entities in the bytecode. Each item
39 * supports a fixed protocol for loading the item on the stack, storing
40 * into it, converting it into a jump condition, and several others.
41 * There are many individual forms of items, such as local, static,
42 * indexed, or instance variables, values on the top of stack, the
43 * special values this or super, etc. Individual items are represented as
44 * inner classes in class Items.
45 *
46 * <p><b>This is NOT part of any supported API.
47 * If you write code that depends on this, you do so at your own risk.
48 * This code and its internal interfaces are subject to change or
49 * deletion without notice.</b>
50 */
51 public class Items {
53 /** The current constant pool.
54 */
55 Pool pool;
57 /** The current code buffer.
58 */
59 Code code;
61 /** The current symbol table.
62 */
63 Symtab syms;
65 /** Type utilities. */
66 Types types;
68 /** Items that exist only once (flyweight pattern).
69 */
70 private final Item voidItem;
71 private final Item thisItem;
72 private final Item superItem;
73 private final Item[] stackItem = new Item[TypeCodeCount];
75 public Items(Pool pool, Code code, Symtab syms, Types types) {
76 this.code = code;
77 this.pool = pool;
78 this.types = types;
79 voidItem = new Item(VOIDcode) {
80 public String toString() { return "void"; }
81 };
82 thisItem = new SelfItem(false);
83 superItem = new SelfItem(true);
84 for (int i = 0; i < VOIDcode; i++) stackItem[i] = new StackItem(i);
85 stackItem[VOIDcode] = voidItem;
86 this.syms = syms;
87 }
89 /** Make a void item
90 */
91 Item makeVoidItem() {
92 return voidItem;
93 }
94 /** Make an item representing `this'.
95 */
96 Item makeThisItem() {
97 return thisItem;
98 }
100 /** Make an item representing `super'.
101 */
102 Item makeSuperItem() {
103 return superItem;
104 }
106 /** Make an item representing a value on stack.
107 * @param type The value's type.
108 */
109 Item makeStackItem(Type type) {
110 return stackItem[Code.typecode(type)];
111 }
113 /** Make an item representing a dynamically invoked method.
114 * @param member The represented symbol.
115 */
116 Item makeDynamicItem(Symbol member) {
117 return new DynamicItem(member);
118 }
120 /** Make an item representing an indexed expression.
121 * @param type The expression's type.
122 */
123 Item makeIndexedItem(Type type) {
124 return new IndexedItem(type);
125 }
127 /** Make an item representing a local variable.
128 * @param v The represented variable.
129 */
130 LocalItem makeLocalItem(VarSymbol v) {
131 return new LocalItem(v.erasure(types), v.adr);
132 }
134 /** Make an item representing a local anonymous variable.
135 * @param type The represented variable's type.
136 * @param reg The represented variable's register.
137 */
138 private LocalItem makeLocalItem(Type type, int reg) {
139 return new LocalItem(type, reg);
140 }
142 /** Make an item representing a static variable or method.
143 * @param member The represented symbol.
144 */
145 Item makeStaticItem(Symbol member) {
146 return new StaticItem(member);
147 }
149 /** Make an item representing an instance variable or method.
150 * @param member The represented symbol.
151 * @param nonvirtual Is the reference not virtual? (true for constructors
152 * and private members).
153 */
154 Item makeMemberItem(Symbol member, boolean nonvirtual) {
155 return new MemberItem(member, nonvirtual);
156 }
158 /** Make an item representing a literal.
159 * @param type The literal's type.
160 * @param value The literal's value.
161 */
162 Item makeImmediateItem(Type type, Object value) {
163 return new ImmediateItem(type, value);
164 }
166 /** Make an item representing an assignment expression.
167 * @param lhs The item representing the assignment's left hand side.
168 */
169 Item makeAssignItem(Item lhs) {
170 return new AssignItem(lhs);
171 }
173 /** Make an item representing a conditional or unconditional jump.
174 * @param opcode The jump's opcode.
175 * @param trueJumps A chain encomassing all jumps that can be taken
176 * if the condition evaluates to true.
177 * @param falseJumps A chain encomassing all jumps that can be taken
178 * if the condition evaluates to false.
179 */
180 CondItem makeCondItem(int opcode, Chain trueJumps, Chain falseJumps) {
181 return new CondItem(opcode, trueJumps, falseJumps);
182 }
184 /** Make an item representing a conditional or unconditional jump.
185 * @param opcode The jump's opcode.
186 */
187 CondItem makeCondItem(int opcode) {
188 return makeCondItem(opcode, null, null);
189 }
191 /** The base class of all items, which implements default behavior.
192 */
193 abstract class Item {
195 /** The type code of values represented by this item.
196 */
197 int typecode;
199 Item(int typecode) {
200 this.typecode = typecode;
201 }
203 /** Generate code to load this item onto stack.
204 */
205 Item load() {
206 throw new AssertionError();
207 }
209 /** Generate code to store top of stack into this item.
210 */
211 void store() {
212 throw new AssertionError("store unsupported: " + this);
213 }
215 /** Generate code to invoke method represented by this item.
216 */
217 Item invoke() {
218 throw new AssertionError(this);
219 }
221 /** Generate code to use this item twice.
222 */
223 void duplicate() {}
225 /** Generate code to avoid having to use this item.
226 */
227 void drop() {}
229 /** Generate code to stash a copy of top of stack - of typecode toscode -
230 * under this item.
231 */
232 void stash(int toscode) {
233 stackItem[toscode].duplicate();
234 }
236 /** Generate code to turn item into a testable condition.
237 */
238 CondItem mkCond() {
239 load();
240 return makeCondItem(ifne);
241 }
243 /** Generate code to coerce item to given type code.
244 * @param targetcode The type code to coerce to.
245 */
246 Item coerce(int targetcode) {
247 if (typecode == targetcode)
248 return this;
249 else {
250 load();
251 int typecode1 = Code.truncate(typecode);
252 int targetcode1 = Code.truncate(targetcode);
253 if (typecode1 != targetcode1) {
254 int offset = targetcode1 > typecode1 ? targetcode1 - 1
255 : targetcode1;
256 code.emitop0(i2l + typecode1 * 3 + offset);
257 }
258 if (targetcode != targetcode1) {
259 code.emitop0(int2byte + targetcode - BYTEcode);
260 }
261 return stackItem[targetcode];
262 }
263 }
265 /** Generate code to coerce item to given type.
266 * @param targettype The type to coerce to.
267 */
268 Item coerce(Type targettype) {
269 return coerce(Code.typecode(targettype));
270 }
272 /** Return the width of this item on stack as a number of words.
273 */
274 int width() {
275 return 0;
276 }
278 public abstract String toString();
279 }
281 /** An item representing a value on stack.
282 */
283 class StackItem extends Item {
285 StackItem(int typecode) {
286 super(typecode);
287 }
289 Item load() {
290 return this;
291 }
293 void duplicate() {
294 code.emitop0(width() == 2 ? dup2 : dup);
295 }
297 void drop() {
298 code.emitop0(width() == 2 ? pop2 : pop);
299 }
301 void stash(int toscode) {
302 code.emitop0(
303 (width() == 2 ? dup_x2 : dup_x1) + 3 * (Code.width(toscode) - 1));
304 }
306 int width() {
307 return Code.width(typecode);
308 }
310 public String toString() {
311 return "stack(" + typecodeNames[typecode] + ")";
312 }
313 }
315 /** An item representing an indexed expression.
316 */
317 class IndexedItem extends Item {
319 IndexedItem(Type type) {
320 super(Code.typecode(type));
321 }
323 Item load() {
324 code.emitop0(iaload + typecode);
325 return stackItem[typecode];
326 }
328 void store() {
329 code.emitop0(iastore + typecode);
330 }
332 void duplicate() {
333 code.emitop0(dup2);
334 }
336 void drop() {
337 code.emitop0(pop2);
338 }
340 void stash(int toscode) {
341 code.emitop0(dup_x2 + 3 * (Code.width(toscode) - 1));
342 }
344 int width() {
345 return 2;
346 }
348 public String toString() {
349 return "indexed(" + ByteCodes.typecodeNames[typecode] + ")";
350 }
351 }
353 /** An item representing `this' or `super'.
354 */
355 class SelfItem extends Item {
357 /** Flag which determines whether this item represents `this' or `super'.
358 */
359 boolean isSuper;
361 SelfItem(boolean isSuper) {
362 super(OBJECTcode);
363 this.isSuper = isSuper;
364 }
366 Item load() {
367 code.emitop0(aload_0);
368 return stackItem[typecode];
369 }
371 public String toString() {
372 return isSuper ? "super" : "this";
373 }
374 }
376 /** An item representing a local variable.
377 */
378 class LocalItem extends Item {
380 /** The variable's register.
381 */
382 int reg;
384 /** The variable's type.
385 */
386 Type type;
388 LocalItem(Type type, int reg) {
389 super(Code.typecode(type));
390 Assert.check(reg >= 0);
391 this.type = type;
392 this.reg = reg;
393 }
395 Item load() {
396 if (reg <= 3)
397 code.emitop0(iload_0 + Code.truncate(typecode) * 4 + reg);
398 else
399 code.emitop1w(iload + Code.truncate(typecode), reg);
400 return stackItem[typecode];
401 }
403 void store() {
404 if (reg <= 3)
405 code.emitop0(istore_0 + Code.truncate(typecode) * 4 + reg);
406 else
407 code.emitop1w(istore + Code.truncate(typecode), reg);
408 code.setDefined(reg);
409 }
411 void incr(int x) {
412 if (typecode == INTcode && x >= -32768 && x <= 32767) {
413 code.emitop1w(iinc, reg, x);
414 } else {
415 load();
416 if (x >= 0) {
417 makeImmediateItem(syms.intType, x).load();
418 code.emitop0(iadd);
419 } else {
420 makeImmediateItem(syms.intType, -x).load();
421 code.emitop0(isub);
422 }
423 makeStackItem(syms.intType).coerce(typecode);
424 store();
425 }
426 }
428 public String toString() {
429 return "localItem(type=" + type + "; reg=" + reg + ")";
430 }
431 }
433 /** An item representing a static variable or method.
434 */
435 class StaticItem extends Item {
437 /** The represented symbol.
438 */
439 Symbol member;
441 StaticItem(Symbol member) {
442 super(Code.typecode(member.erasure(types)));
443 this.member = member;
444 }
446 Item load() {
447 code.emitop2(getstatic, pool.put(member));
448 return stackItem[typecode];
449 }
451 void store() {
452 code.emitop2(putstatic, pool.put(member));
453 }
455 Item invoke() {
456 MethodType mtype = (MethodType)member.erasure(types);
457 int rescode = Code.typecode(mtype.restype);
458 code.emitInvokestatic(pool.put(member), mtype);
459 return stackItem[rescode];
460 }
462 public String toString() {
463 return "static(" + member + ")";
464 }
465 }
467 /** An item representing a dynamic call site.
468 */
469 class DynamicItem extends StaticItem {
470 DynamicItem(Symbol member) {
471 super(member);
472 }
474 Item load() {
475 assert false;
476 return null;
477 }
479 void store() {
480 assert false;
481 }
483 Item invoke() {
484 // assert target.hasNativeInvokeDynamic();
485 MethodType mtype = (MethodType)member.erasure(types);
486 int rescode = Code.typecode(mtype.restype);
487 code.emitInvokedynamic(pool.put(member), mtype);
488 return stackItem[rescode];
489 }
491 public String toString() {
492 return "dynamic(" + member + ")";
493 }
494 }
496 /** An item representing an instance variable or method.
497 */
498 class MemberItem extends Item {
500 /** The represented symbol.
501 */
502 Symbol member;
504 /** Flag that determines whether or not access is virtual.
505 */
506 boolean nonvirtual;
508 MemberItem(Symbol member, boolean nonvirtual) {
509 super(Code.typecode(member.erasure(types)));
510 this.member = member;
511 this.nonvirtual = nonvirtual;
512 }
514 Item load() {
515 code.emitop2(getfield, pool.put(member));
516 return stackItem[typecode];
517 }
519 void store() {
520 code.emitop2(putfield, pool.put(member));
521 }
523 Item invoke() {
524 MethodType mtype = (MethodType)member.externalType(types);
525 int rescode = Code.typecode(mtype.restype);
526 if ((member.owner.flags() & Flags.INTERFACE) != 0 && !nonvirtual) {
527 code.emitInvokeinterface(pool.put(member), mtype);
528 } else if (nonvirtual) {
529 code.emitInvokespecial(pool.put(member), mtype);
530 } else {
531 code.emitInvokevirtual(pool.put(member), mtype);
532 }
533 return stackItem[rescode];
534 }
536 void duplicate() {
537 stackItem[OBJECTcode].duplicate();
538 }
540 void drop() {
541 stackItem[OBJECTcode].drop();
542 }
544 void stash(int toscode) {
545 stackItem[OBJECTcode].stash(toscode);
546 }
548 int width() {
549 return 1;
550 }
552 public String toString() {
553 return "member(" + member + (nonvirtual ? " nonvirtual)" : ")");
554 }
555 }
557 /** An item representing a literal.
558 */
559 class ImmediateItem extends Item {
561 /** The literal's value.
562 */
563 Object value;
565 ImmediateItem(Type type, Object value) {
566 super(Code.typecode(type));
567 this.value = value;
568 }
570 private void ldc() {
571 int idx = pool.put(value);
572 if (typecode == LONGcode || typecode == DOUBLEcode) {
573 code.emitop2(ldc2w, idx);
574 } else {
575 code.emitLdc(idx);
576 }
577 }
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 }
634 CondItem mkCond() {
635 int ival = ((Number)value).intValue();
636 return makeCondItem(ival != 0 ? goto_ : dontgoto);
637 }
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 }
681 public String toString() {
682 return "immediate(" + value + ")";
683 }
684 }
686 /** An item representing an assignment expressions.
687 */
688 class AssignItem extends Item {
690 /** The item representing the assignment's left hand side.
691 */
692 Item lhs;
694 AssignItem(Item lhs) {
695 super(lhs.typecode);
696 this.lhs = lhs;
697 }
699 Item load() {
700 lhs.stash(typecode);
701 lhs.store();
702 return stackItem[typecode];
703 }
705 void duplicate() {
706 load().duplicate();
707 }
709 void drop() {
710 lhs.store();
711 }
713 void stash(int toscode) {
714 Assert.error();
715 }
717 int width() {
718 return lhs.width() + Code.width(typecode);
719 }
721 public String toString() {
722 return "assign(lhs = " + lhs + ")";
723 }
724 }
726 /** An item representing a conditional or unconditional jump.
727 */
728 class CondItem extends Item {
730 /** A chain encomassing all jumps that can be taken
731 * if the condition evaluates to true.
732 */
733 Chain trueJumps;
735 /** A chain encomassing all jumps that can be taken
736 * if the condition evaluates to false.
737 */
738 Chain falseJumps;
740 /** The jump's opcode.
741 */
742 int opcode;
744 /*
745 * An abstract syntax tree of this item. It is needed
746 * for branch entries in 'CharacterRangeTable' attribute.
747 */
748 JCTree tree;
750 CondItem(int opcode, Chain truejumps, Chain falsejumps) {
751 super(BYTEcode);
752 this.opcode = opcode;
753 this.trueJumps = truejumps;
754 this.falseJumps = falsejumps;
755 }
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 }
773 void duplicate() {
774 load().duplicate();
775 }
777 void drop() {
778 load().drop();
779 }
781 void stash(int toscode) {
782 Assert.error();
783 }
785 CondItem mkCond() {
786 return this;
787 }
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.curPc();
793 Chain c = Code.mergeChains(trueJumps, code.branch(opcode));
794 code.crt.put(tree, CRTable.CRT_BRANCH_TRUE, startpc, code.curPc());
795 return c;
796 }
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.curPc();
802 Chain c = Code.mergeChains(falseJumps, code.branch(Code.negate(opcode)));
803 code.crt.put(tree, CRTable.CRT_BRANCH_FALSE, startpc, code.curPc());
804 return c;
805 }
807 CondItem negate() {
808 CondItem c = new CondItem(Code.negate(opcode), falseJumps, trueJumps);
809 c.tree = tree;
810 return c;
811 }
813 int width() {
814 // a CondItem doesn't have a size on the stack per se.
815 throw new AssertionError();
816 }
818 boolean isTrue() {
819 return falseJumps == null && opcode == goto_;
820 }
822 boolean isFalse() {
823 return trueJumps == null && opcode == dontgoto;
824 }
826 public String toString() {
827 return "cond(" + Code.mnem(opcode) + ")";
828 }
829 }
830 }