Sat, 01 Dec 2007 00:00:00 +0000
Initial load
1 /*
2 * Copyright 1999-2007 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
26 package com.sun.tools.javac.jvm;
28 import com.sun.tools.javac.util.*;
29 import com.sun.tools.javac.code.*;
31 import com.sun.tools.javac.code.Symbol.*;
32 import com.sun.tools.javac.code.Type.*;
33 import com.sun.tools.javac.jvm.Code.*;
34 import com.sun.tools.javac.tree.JCTree;
36 import static com.sun.tools.javac.code.TypeTags.*;
37 import static com.sun.tools.javac.jvm.ByteCodes.*;
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 API supported by Sun Microsystems. If
49 * 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 {
55 /** The current constant pool.
56 */
57 Pool pool;
59 /** The current code buffer.
60 */
61 Code code;
63 /** The current symbol table.
64 */
65 Symtab syms;
67 /** Type utilities. */
68 Types types;
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];
77 public Items(Pool pool, Code code, Symtab syms, Types types) {
78 this.code = code;
79 this.pool = pool;
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 }
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 }
102 /** Make an item representing `super'.
103 */
104 Item makeSuperItem() {
105 return superItem;
106 }
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 }
115 /** Make an item representing an indexed expression.
116 * @param type The expression's type.
117 */
118 Item makeIndexedItem(Type type) {
119 return new IndexedItem(type);
120 }
122 /** Make an item representing a local variable.
123 * @param v The represented variable.
124 */
125 LocalItem makeLocalItem(VarSymbol v) {
126 return new LocalItem(v.erasure(types), v.adr);
127 }
129 /** Make an item representing a local anonymous variable.
130 * @param type The represented variable's type.
131 * @param reg The represented variable's register.
132 */
133 private LocalItem makeLocalItem(Type type, int reg) {
134 return new LocalItem(type, reg);
135 }
137 /** Make an item representing a static variable or method.
138 * @param member The represented symbol.
139 */
140 Item makeStaticItem(Symbol member) {
141 return new StaticItem(member);
142 }
144 /** Make an item representing an instance variable or method.
145 * @param member The represented symbol.
146 * @param nonvirtual Is the reference not virtual? (true for constructors
147 * and private members).
148 */
149 Item makeMemberItem(Symbol member, boolean nonvirtual) {
150 return new MemberItem(member, nonvirtual);
151 }
153 /** Make an item representing a literal.
154 * @param type The literal's type.
155 * @param value The literal's value.
156 */
157 Item makeImmediateItem(Type type, Object value) {
158 return new ImmediateItem(type, value);
159 }
161 /** Make an item representing an assignment expression.
162 * @param lhs The item representing the assignment's left hand side.
163 */
164 Item makeAssignItem(Item lhs) {
165 return new AssignItem(lhs);
166 }
168 /** Make an item representing a conditional or unconditional jump.
169 * @param opcode The jump's opcode.
170 * @param trueJumps A chain encomassing all jumps that can be taken
171 * if the condition evaluates to true.
172 * @param falseJumps A chain encomassing all jumps that can be taken
173 * if the condition evaluates to false.
174 */
175 CondItem makeCondItem(int opcode, Chain trueJumps, Chain falseJumps) {
176 return new CondItem(opcode, trueJumps, falseJumps);
177 }
179 /** Make an item representing a conditional or unconditional jump.
180 * @param opcode The jump's opcode.
181 */
182 CondItem makeCondItem(int opcode) {
183 return makeCondItem(opcode, null, null);
184 }
186 /** The base class of all items, which implements default behavior.
187 */
188 abstract class Item {
190 /** The type code of values represented by this item.
191 */
192 int typecode;
194 Item(int typecode) {
195 this.typecode = typecode;
196 }
198 /** Generate code to load this item onto stack.
199 */
200 Item load() {
201 throw new AssertionError();
202 }
204 /** Generate code to store top of stack into this item.
205 */
206 void store() {
207 throw new AssertionError("store unsupported: " + this);
208 }
210 /** Generate code to invoke method represented by this item.
211 */
212 Item invoke() {
213 throw new AssertionError(this);
214 }
216 /** Generate code to use this item twice.
217 */
218 void duplicate() {}
220 /** Generate code to avoid having to use this item.
221 */
222 void drop() {}
224 /** Generate code to stash a copy of top of stack - of typecode toscode -
225 * under this item.
226 */
227 void stash(int toscode) {
228 stackItem[toscode].duplicate();
229 }
231 /** Generate code to turn item into a testable condition.
232 */
233 CondItem mkCond() {
234 load();
235 return makeCondItem(ifne);
236 }
238 /** Generate code to coerce item to given type code.
239 * @param targetcode The type code to coerce to.
240 */
241 Item coerce(int targetcode) {
242 if (typecode == targetcode)
243 return this;
244 else {
245 load();
246 int typecode1 = Code.truncate(typecode);
247 int targetcode1 = Code.truncate(targetcode);
248 if (typecode1 != targetcode1) {
249 int offset = targetcode1 > typecode1 ? targetcode1 - 1
250 : targetcode1;
251 code.emitop0(i2l + typecode1 * 3 + offset);
252 }
253 if (targetcode != targetcode1) {
254 code.emitop0(int2byte + targetcode - BYTEcode);
255 }
256 return stackItem[targetcode];
257 }
258 }
260 /** Generate code to coerce item to given type.
261 * @param targettype The type to coerce to.
262 */
263 Item coerce(Type targettype) {
264 return coerce(Code.typecode(targettype));
265 }
267 /** Return the width of this item on stack as a number of words.
268 */
269 int width() {
270 return 0;
271 }
273 public abstract String toString();
274 }
276 /** An item representing a value on stack.
277 */
278 class StackItem extends Item {
280 StackItem(int typecode) {
281 super(typecode);
282 }
284 Item load() {
285 return this;
286 }
288 void duplicate() {
289 code.emitop0(width() == 2 ? dup2 : dup);
290 }
292 void drop() {
293 code.emitop0(width() == 2 ? pop2 : pop);
294 }
296 void stash(int toscode) {
297 code.emitop0(
298 (width() == 2 ? dup_x2 : dup_x1) + 3 * (Code.width(toscode) - 1));
299 }
301 int width() {
302 return Code.width(typecode);
303 }
305 public String toString() {
306 return "stack(" + typecodeNames[typecode] + ")";
307 }
308 }
310 /** An item representing an indexed expression.
311 */
312 class IndexedItem extends Item {
314 IndexedItem(Type type) {
315 super(Code.typecode(type));
316 }
318 Item load() {
319 code.emitop0(iaload + typecode);
320 return stackItem[typecode];
321 }
323 void store() {
324 code.emitop0(iastore + typecode);
325 }
327 void duplicate() {
328 code.emitop0(dup2);
329 }
331 void drop() {
332 code.emitop0(pop2);
333 }
335 void stash(int toscode) {
336 code.emitop0(dup_x2 + 3 * (Code.width(toscode) - 1));
337 }
339 int width() {
340 return 2;
341 }
343 public String toString() {
344 return "indexed(" + ByteCodes.typecodeNames[typecode] + ")";
345 }
346 }
348 /** An item representing `this' or `super'.
349 */
350 class SelfItem extends Item {
352 /** Flag which determines whether this item represents `this' or `super'.
353 */
354 boolean isSuper;
356 SelfItem(boolean isSuper) {
357 super(OBJECTcode);
358 this.isSuper = isSuper;
359 }
361 Item load() {
362 code.emitop0(aload_0);
363 return stackItem[typecode];
364 }
366 public String toString() {
367 return isSuper ? "super" : "this";
368 }
369 }
371 /** An item representing a local variable.
372 */
373 class LocalItem extends Item {
375 /** The variable's register.
376 */
377 int reg;
379 /** The variable's type.
380 */
381 Type type;
383 LocalItem(Type type, int reg) {
384 super(Code.typecode(type));
385 assert reg >= 0;
386 this.type = type;
387 this.reg = reg;
388 }
390 Item load() {
391 if (reg <= 3)
392 code.emitop0(iload_0 + Code.truncate(typecode) * 4 + reg);
393 else
394 code.emitop1w(iload + Code.truncate(typecode), reg);
395 return stackItem[typecode];
396 }
398 void store() {
399 if (reg <= 3)
400 code.emitop0(istore_0 + Code.truncate(typecode) * 4 + reg);
401 else
402 code.emitop1w(istore + Code.truncate(typecode), reg);
403 code.setDefined(reg);
404 }
406 void incr(int x) {
407 if (typecode == INTcode && x >= -32768 && x <= 32767) {
408 code.emitop1w(iinc, reg, x);
409 } else {
410 load();
411 if (x >= 0) {
412 makeImmediateItem(syms.intType, x).load();
413 code.emitop0(iadd);
414 } else {
415 makeImmediateItem(syms.intType, -x).load();
416 code.emitop0(isub);
417 }
418 makeStackItem(syms.intType).coerce(typecode);
419 store();
420 }
421 }
423 public String toString() {
424 return "localItem(type=" + type + "; reg=" + reg + ")";
425 }
426 }
428 /** An item representing a static variable or method.
429 */
430 class StaticItem extends Item {
432 /** The represented symbol.
433 */
434 Symbol member;
436 StaticItem(Symbol member) {
437 super(Code.typecode(member.erasure(types)));
438 this.member = member;
439 }
441 Item load() {
442 code.emitop2(getstatic, pool.put(member));
443 return stackItem[typecode];
444 }
446 void store() {
447 code.emitop2(putstatic, pool.put(member));
448 }
450 Item invoke() {
451 MethodType mtype = (MethodType)member.erasure(types);
452 int argsize = Code.width(mtype.argtypes);
453 int rescode = Code.typecode(mtype.restype);
454 int sdiff = Code.width(rescode) - argsize;
455 code.emitInvokestatic(pool.put(member), mtype);
456 return stackItem[rescode];
457 }
459 public String toString() {
460 return "static(" + member + ")";
461 }
462 }
464 /** An item representing an instance variable or method.
465 */
466 class MemberItem extends Item {
468 /** The represented symbol.
469 */
470 Symbol member;
472 /** Flag that determines whether or not access is virtual.
473 */
474 boolean nonvirtual;
476 MemberItem(Symbol member, boolean nonvirtual) {
477 super(Code.typecode(member.erasure(types)));
478 this.member = member;
479 this.nonvirtual = nonvirtual;
480 }
482 Item load() {
483 code.emitop2(getfield, pool.put(member));
484 return stackItem[typecode];
485 }
487 void store() {
488 code.emitop2(putfield, pool.put(member));
489 }
491 Item invoke() {
492 MethodType mtype = (MethodType)member.externalType(types);
493 int rescode = Code.typecode(mtype.restype);
494 if ((member.owner.flags() & Flags.INTERFACE) != 0) {
495 code.emitInvokeinterface(pool.put(member), mtype);
496 } else if (nonvirtual) {
497 code.emitInvokespecial(pool.put(member), mtype);
498 } else {
499 code.emitInvokevirtual(pool.put(member), mtype);
500 }
501 return stackItem[rescode];
502 }
504 void duplicate() {
505 stackItem[OBJECTcode].duplicate();
506 }
508 void drop() {
509 stackItem[OBJECTcode].drop();
510 }
512 void stash(int toscode) {
513 stackItem[OBJECTcode].stash(toscode);
514 }
516 int width() {
517 return 1;
518 }
520 public String toString() {
521 return "member(" + member + (nonvirtual ? " nonvirtual)" : ")");
522 }
523 }
525 /** An item representing a literal.
526 */
527 class ImmediateItem extends Item {
529 /** The literal's value.
530 */
531 Object value;
533 ImmediateItem(Type type, Object value) {
534 super(Code.typecode(type));
535 this.value = value;
536 }
538 private void ldc() {
539 int idx = pool.put(value);
540 if (typecode == LONGcode || typecode == DOUBLEcode) {
541 code.emitop2(ldc2w, idx);
542 } else if (idx <= 255) {
543 code.emitop1(ldc1, idx);
544 } else {
545 code.emitop2(ldc2, idx);
546 }
547 }
549 Item load() {
550 switch (typecode) {
551 case INTcode: case BYTEcode: case SHORTcode: case CHARcode:
552 int ival = ((Number)value).intValue();
553 if (-1 <= ival && ival <= 5)
554 code.emitop0(iconst_0 + ival);
555 else if (Byte.MIN_VALUE <= ival && ival <= Byte.MAX_VALUE)
556 code.emitop1(bipush, ival);
557 else if (Short.MIN_VALUE <= ival && ival <= Short.MAX_VALUE)
558 code.emitop2(sipush, ival);
559 else
560 ldc();
561 break;
562 case LONGcode:
563 long lval = ((Number)value).longValue();
564 if (lval == 0 || lval == 1)
565 code.emitop0(lconst_0 + (int)lval);
566 else
567 ldc();
568 break;
569 case FLOATcode:
570 float fval = ((Number)value).floatValue();
571 if (isPosZero(fval) || fval == 1.0 || fval == 2.0)
572 code.emitop0(fconst_0 + (int)fval);
573 else {
574 ldc();
575 }
576 break;
577 case DOUBLEcode:
578 double dval = ((Number)value).doubleValue();
579 if (isPosZero(dval) || dval == 1.0)
580 code.emitop0(dconst_0 + (int)dval);
581 else
582 ldc();
583 break;
584 case OBJECTcode:
585 ldc();
586 break;
587 default:
588 assert false;
589 }
590 return stackItem[typecode];
591 }
592 //where
593 /** Return true iff float number is positive 0.
594 */
595 private boolean isPosZero(float x) {
596 return x == 0.0f && 1.0f / x > 0.0f;
597 }
598 /** Return true iff double number is positive 0.
599 */
600 private boolean isPosZero(double x) {
601 return x == 0.0d && 1.0d / x > 0.0d;
602 }
604 CondItem mkCond() {
605 int ival = ((Number)value).intValue();
606 return makeCondItem(ival != 0 ? goto_ : dontgoto);
607 }
609 Item coerce(int targetcode) {
610 if (typecode == targetcode) {
611 return this;
612 } else {
613 switch (targetcode) {
614 case INTcode:
615 if (Code.truncate(typecode) == INTcode)
616 return this;
617 else
618 return new ImmediateItem(
619 syms.intType,
620 ((Number)value).intValue());
621 case LONGcode:
622 return new ImmediateItem(
623 syms.longType,
624 ((Number)value).longValue());
625 case FLOATcode:
626 return new ImmediateItem(
627 syms.floatType,
628 ((Number)value).floatValue());
629 case DOUBLEcode:
630 return new ImmediateItem(
631 syms.doubleType,
632 ((Number)value).doubleValue());
633 case BYTEcode:
634 return new ImmediateItem(
635 syms.byteType,
636 (int)(byte)((Number)value).intValue());
637 case CHARcode:
638 return new ImmediateItem(
639 syms.charType,
640 (int)(char)((Number)value).intValue());
641 case SHORTcode:
642 return new ImmediateItem(
643 syms.shortType,
644 (int)(short)((Number)value).intValue());
645 default:
646 return super.coerce(targetcode);
647 }
648 }
649 }
651 public String toString() {
652 return "immediate(" + value + ")";
653 }
654 }
656 /** An item representing an assignment expressions.
657 */
658 class AssignItem extends Item {
660 /** The item representing the assignment's left hand side.
661 */
662 Item lhs;
664 AssignItem(Item lhs) {
665 super(lhs.typecode);
666 this.lhs = lhs;
667 }
669 Item load() {
670 lhs.stash(typecode);
671 lhs.store();
672 return stackItem[typecode];
673 }
675 void duplicate() {
676 load().duplicate();
677 }
679 void drop() {
680 lhs.store();
681 }
683 void stash(int toscode) {
684 assert false;
685 }
687 int width() {
688 return lhs.width() + Code.width(typecode);
689 }
691 public String toString() {
692 return "assign(lhs = " + lhs + ")";
693 }
694 }
696 /** An item representing a conditional or unconditional jump.
697 */
698 class CondItem extends Item {
700 /** A chain encomassing all jumps that can be taken
701 * if the condition evaluates to true.
702 */
703 Chain trueJumps;
705 /** A chain encomassing all jumps that can be taken
706 * if the condition evaluates to false.
707 */
708 Chain falseJumps;
710 /** The jump's opcode.
711 */
712 int opcode;
714 /*
715 * An abstract syntax tree of this item. It is needed
716 * for branch entries in 'CharacterRangeTable' attribute.
717 */
718 JCTree tree;
720 CondItem(int opcode, Chain truejumps, Chain falsejumps) {
721 super(BYTEcode);
722 this.opcode = opcode;
723 this.trueJumps = truejumps;
724 this.falseJumps = falsejumps;
725 }
727 Item load() {
728 Chain trueChain = null;
729 Chain falseChain = jumpFalse();
730 if (!isFalse()) {
731 code.resolve(trueJumps);
732 code.emitop0(iconst_1);
733 trueChain = code.branch(goto_);
734 }
735 if (falseChain != null) {
736 code.resolve(falseChain);
737 code.emitop0(iconst_0);
738 }
739 code.resolve(trueChain);
740 return stackItem[typecode];
741 }
743 void duplicate() {
744 load().duplicate();
745 }
747 void drop() {
748 load().drop();
749 }
751 void stash(int toscode) {
752 assert false;
753 }
755 CondItem mkCond() {
756 return this;
757 }
759 Chain jumpTrue() {
760 if (tree == null) return code.mergeChains(trueJumps, code.branch(opcode));
761 // we should proceed further in -Xjcov mode only
762 int startpc = code.curPc();
763 Chain c = code.mergeChains(trueJumps, code.branch(opcode));
764 code.crt.put(tree, CRTable.CRT_BRANCH_TRUE, startpc, code.curPc());
765 return c;
766 }
768 Chain jumpFalse() {
769 if (tree == null) return code.mergeChains(falseJumps, code.branch(code.negate(opcode)));
770 // we should proceed further in -Xjcov mode only
771 int startpc = code.curPc();
772 Chain c = code.mergeChains(falseJumps, code.branch(code.negate(opcode)));
773 code.crt.put(tree, CRTable.CRT_BRANCH_FALSE, startpc, code.curPc());
774 return c;
775 }
777 CondItem negate() {
778 CondItem c = new CondItem(code.negate(opcode), falseJumps, trueJumps);
779 c.tree = tree;
780 return c;
781 }
783 int width() {
784 // a CondItem doesn't have a size on the stack per se.
785 throw new AssertionError();
786 }
788 boolean isTrue() {
789 return falseJumps == null && opcode == goto_;
790 }
792 boolean isFalse() {
793 return trueJumps == null && opcode == dontgoto;
794 }
796 public String toString() {
797 return "cond(" + Code.mnem(opcode) + ")";
798 }
799 }
800 }