001: /*
002: * Copyright 1999-2007 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package com.sun.tools.javac.jvm;
027:
028: import com.sun.tools.javac.util.*;
029: import com.sun.tools.javac.code.*;
030:
031: import com.sun.tools.javac.code.Symbol.*;
032: import com.sun.tools.javac.code.Type.*;
033: import com.sun.tools.javac.jvm.Code.*;
034: import com.sun.tools.javac.tree.JCTree;
035:
036: import static com.sun.tools.javac.code.TypeTags.*;
037: import static com.sun.tools.javac.jvm.ByteCodes.*;
038:
039: /** A helper class for code generation. Items are objects
040: * that stand for addressable entities in the bytecode. Each item
041: * supports a fixed protocol for loading the item on the stack, storing
042: * into it, converting it into a jump condition, and several others.
043: * There are many individual forms of items, such as local, static,
044: * indexed, or instance variables, values on the top of stack, the
045: * special values this or super, etc. Individual items are represented as
046: * inner classes in class Items.
047: *
048: * <p><b>This is NOT part of any API supported by Sun Microsystems. If
049: * you write code that depends on this, you do so at your own risk.
050: * This code and its internal interfaces are subject to change or
051: * deletion without notice.</b>
052: */
053: @Version("@(#)Items.java 1.41 07/05/05")
054: public class Items {
055:
056: /** The current constant pool.
057: */
058: Pool pool;
059:
060: /** The current code buffer.
061: */
062: Code code;
063:
064: /** The current symbol table.
065: */
066: Symtab syms;
067:
068: /** Type utilities. */
069: Types types;
070:
071: /** Items that exist only once (flyweight pattern).
072: */
073: private final Item voidItem;
074: private final Item this Item;
075: private final Item super Item;
076: private final Item[] stackItem = new Item[TypeCodeCount];
077:
078: public Items(Pool pool, Code code, Symtab syms, Types types) {
079: this .code = code;
080: this .pool = pool;
081: this .types = types;
082: voidItem = new Item(VOIDcode) {
083: public String toString() {
084: return "void";
085: }
086: };
087: this Item = new SelfItem(false);
088: super Item = new SelfItem(true);
089: for (int i = 0; i < VOIDcode; i++)
090: stackItem[i] = new StackItem(i);
091: stackItem[VOIDcode] = voidItem;
092: this .syms = syms;
093: }
094:
095: /** Make a void item
096: */
097: Item makeVoidItem() {
098: return voidItem;
099: }
100:
101: /** Make an item representing `this'.
102: */
103: Item makeThisItem() {
104: return this Item;
105: }
106:
107: /** Make an item representing `super'.
108: */
109: Item makeSuperItem() {
110: return super Item;
111: }
112:
113: /** Make an item representing a value on stack.
114: * @param type The value's type.
115: */
116: Item makeStackItem(Type type) {
117: return stackItem[Code.typecode(type)];
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:
226: /** Generate code to avoid having to use this item.
227: */
228: void drop() {
229: }
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((width() == 2 ? dup_x2 : dup_x1) + 3
305: * (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 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
400: + reg);
401: else
402: code.emitop1w(iload + Code.truncate(typecode), reg);
403: return stackItem[typecode];
404: }
405:
406: void store() {
407: if (reg <= 3)
408: code.emitop0(istore_0 + Code.truncate(typecode) * 4
409: + reg);
410: else
411: code.emitop1w(istore + Code.truncate(typecode), reg);
412: code.setDefined(reg);
413: }
414:
415: void incr(int x) {
416: if (typecode == INTcode && x >= -32768 && x <= 32767) {
417: code.emitop1w(iinc, reg, x);
418: } else {
419: load();
420: if (x >= 0) {
421: makeImmediateItem(syms.intType, x).load();
422: code.emitop0(iadd);
423: } else {
424: makeImmediateItem(syms.intType, -x).load();
425: code.emitop0(isub);
426: }
427: makeStackItem(syms.intType).coerce(typecode);
428: store();
429: }
430: }
431:
432: public String toString() {
433: return "localItem(type=" + type + "; reg=" + reg + ")";
434: }
435: }
436:
437: /** An item representing a static variable or method.
438: */
439: class StaticItem extends Item {
440:
441: /** The represented symbol.
442: */
443: Symbol member;
444:
445: StaticItem(Symbol member) {
446: super (Code.typecode(member.erasure(types)));
447: this .member = member;
448: }
449:
450: Item load() {
451: code.emitop2(getstatic, pool.put(member));
452: return stackItem[typecode];
453: }
454:
455: void store() {
456: code.emitop2(putstatic, pool.put(member));
457: }
458:
459: Item invoke() {
460: MethodType mtype = (MethodType) member.erasure(types);
461: int argsize = Code.width(mtype.argtypes);
462: int rescode = Code.typecode(mtype.restype);
463: int sdiff = Code.width(rescode) - argsize;
464: code.emitInvokestatic(pool.put(member), mtype);
465: return stackItem[rescode];
466: }
467:
468: public String toString() {
469: return "static(" + member + ")";
470: }
471: }
472:
473: /** An item representing an instance variable or method.
474: */
475: class MemberItem extends Item {
476:
477: /** The represented symbol.
478: */
479: Symbol member;
480:
481: /** Flag that determines whether or not access is virtual.
482: */
483: boolean nonvirtual;
484:
485: MemberItem(Symbol member, boolean nonvirtual) {
486: super (Code.typecode(member.erasure(types)));
487: this .member = member;
488: this .nonvirtual = nonvirtual;
489: }
490:
491: Item load() {
492: code.emitop2(getfield, pool.put(member));
493: return stackItem[typecode];
494: }
495:
496: void store() {
497: code.emitop2(putfield, pool.put(member));
498: }
499:
500: Item invoke() {
501: MethodType mtype = (MethodType) member.externalType(types);
502: int rescode = Code.typecode(mtype.restype);
503: if ((member.owner.flags() & Flags.INTERFACE) != 0) {
504: code.emitInvokeinterface(pool.put(member), mtype);
505: } else if (nonvirtual) {
506: code.emitInvokespecial(pool.put(member), mtype);
507: } else {
508: code.emitInvokevirtual(pool.put(member), mtype);
509: }
510: return stackItem[rescode];
511: }
512:
513: void duplicate() {
514: stackItem[OBJECTcode].duplicate();
515: }
516:
517: void drop() {
518: stackItem[OBJECTcode].drop();
519: }
520:
521: void stash(int toscode) {
522: stackItem[OBJECTcode].stash(toscode);
523: }
524:
525: int width() {
526: return 1;
527: }
528:
529: public String toString() {
530: return "member(" + member
531: + (nonvirtual ? " nonvirtual)" : ")");
532: }
533: }
534:
535: /** An item representing a literal.
536: */
537: class ImmediateItem extends Item {
538:
539: /** The literal's value.
540: */
541: Object value;
542:
543: ImmediateItem(Type type, Object value) {
544: super (Code.typecode(type));
545: this .value = value;
546: }
547:
548: private void ldc() {
549: int idx = pool.put(value);
550: if (typecode == LONGcode || typecode == DOUBLEcode) {
551: code.emitop2(ldc2w, idx);
552: } else if (idx <= 255) {
553: code.emitop1(ldc1, idx);
554: } else {
555: code.emitop2(ldc2, idx);
556: }
557: }
558:
559: Item load() {
560: switch (typecode) {
561: case INTcode:
562: case BYTEcode:
563: case SHORTcode:
564: case CHARcode:
565: int ival = ((Number) value).intValue();
566: if (-1 <= ival && ival <= 5)
567: code.emitop0(iconst_0 + ival);
568: else if (Byte.MIN_VALUE <= ival
569: && ival <= Byte.MAX_VALUE)
570: code.emitop1(bipush, ival);
571: else if (Short.MIN_VALUE <= ival
572: && ival <= Short.MAX_VALUE)
573: code.emitop2(sipush, ival);
574: else
575: ldc();
576: break;
577: case LONGcode:
578: long lval = ((Number) value).longValue();
579: if (lval == 0 || lval == 1)
580: code.emitop0(lconst_0 + (int) lval);
581: else
582: ldc();
583: break;
584: case FLOATcode:
585: float fval = ((Number) value).floatValue();
586: if (isPosZero(fval) || fval == 1.0 || fval == 2.0)
587: code.emitop0(fconst_0 + (int) fval);
588: else {
589: ldc();
590: }
591: break;
592: case DOUBLEcode:
593: double dval = ((Number) value).doubleValue();
594: if (isPosZero(dval) || dval == 1.0)
595: code.emitop0(dconst_0 + (int) dval);
596: else
597: ldc();
598: break;
599: case OBJECTcode:
600: ldc();
601: break;
602: default:
603: assert false;
604: }
605: return stackItem[typecode];
606: }
607:
608: //where
609: /** Return true iff float number is positive 0.
610: */
611: private boolean isPosZero(float x) {
612: return x == 0.0f && 1.0f / x > 0.0f;
613: }
614:
615: /** Return true iff double number is positive 0.
616: */
617: private boolean isPosZero(double x) {
618: return x == 0.0d && 1.0d / x > 0.0d;
619: }
620:
621: CondItem mkCond() {
622: int ival = ((Number) value).intValue();
623: return makeCondItem(ival != 0 ? goto_ : dontgoto);
624: }
625:
626: Item coerce(int targetcode) {
627: if (typecode == targetcode) {
628: return this ;
629: } else {
630: switch (targetcode) {
631: case INTcode:
632: if (Code.truncate(typecode) == INTcode)
633: return this ;
634: else
635: return new ImmediateItem(syms.intType,
636: ((Number) value).intValue());
637: case LONGcode:
638: return new ImmediateItem(syms.longType,
639: ((Number) value).longValue());
640: case FLOATcode:
641: return new ImmediateItem(syms.floatType,
642: ((Number) value).floatValue());
643: case DOUBLEcode:
644: return new ImmediateItem(syms.doubleType,
645: ((Number) value).doubleValue());
646: case BYTEcode:
647: return new ImmediateItem(syms.byteType,
648: (int) (byte) ((Number) value).intValue());
649: case CHARcode:
650: return new ImmediateItem(syms.charType,
651: (int) (char) ((Number) value).intValue());
652: case SHORTcode:
653: return new ImmediateItem(syms.shortType,
654: (int) (short) ((Number) value).intValue());
655: default:
656: return super .coerce(targetcode);
657: }
658: }
659: }
660:
661: public String toString() {
662: return "immediate(" + value + ")";
663: }
664: }
665:
666: /** An item representing an assignment expressions.
667: */
668: class AssignItem extends Item {
669:
670: /** The item representing the assignment's left hand side.
671: */
672: Item lhs;
673:
674: AssignItem(Item lhs) {
675: super (lhs.typecode);
676: this .lhs = lhs;
677: }
678:
679: Item load() {
680: lhs.stash(typecode);
681: lhs.store();
682: return stackItem[typecode];
683: }
684:
685: void duplicate() {
686: load().duplicate();
687: }
688:
689: void drop() {
690: lhs.store();
691: }
692:
693: void stash(int toscode) {
694: assert false;
695: }
696:
697: int width() {
698: return lhs.width() + Code.width(typecode);
699: }
700:
701: public String toString() {
702: return "assign(lhs = " + lhs + ")";
703: }
704: }
705:
706: /** An item representing a conditional or unconditional jump.
707: */
708: class CondItem extends Item {
709:
710: /** A chain encomassing all jumps that can be taken
711: * if the condition evaluates to true.
712: */
713: Chain trueJumps;
714:
715: /** A chain encomassing all jumps that can be taken
716: * if the condition evaluates to false.
717: */
718: Chain falseJumps;
719:
720: /** The jump's opcode.
721: */
722: int opcode;
723:
724: /*
725: * An abstract syntax tree of this item. It is needed
726: * for branch entries in 'CharacterRangeTable' attribute.
727: */
728: JCTree tree;
729:
730: CondItem(int opcode, Chain truejumps, Chain falsejumps) {
731: super (BYTEcode);
732: this .opcode = opcode;
733: this .trueJumps = truejumps;
734: this .falseJumps = falsejumps;
735: }
736:
737: Item load() {
738: Chain trueChain = null;
739: Chain falseChain = jumpFalse();
740: if (!isFalse()) {
741: code.resolve(trueJumps);
742: code.emitop0(iconst_1);
743: trueChain = code.branch(goto_);
744: }
745: if (falseChain != null) {
746: code.resolve(falseChain);
747: code.emitop0(iconst_0);
748: }
749: code.resolve(trueChain);
750: return stackItem[typecode];
751: }
752:
753: void duplicate() {
754: load().duplicate();
755: }
756:
757: void drop() {
758: load().drop();
759: }
760:
761: void stash(int toscode) {
762: assert false;
763: }
764:
765: CondItem mkCond() {
766: return this ;
767: }
768:
769: Chain jumpTrue() {
770: if (tree == null)
771: return code.mergeChains(trueJumps, code.branch(opcode));
772: // we should proceed further in -Xjcov mode only
773: int startpc = code.curPc();
774: Chain c = code.mergeChains(trueJumps, code.branch(opcode));
775: code.crt.put(tree, CRTable.CRT_BRANCH_TRUE, startpc, code
776: .curPc());
777: return c;
778: }
779:
780: Chain jumpFalse() {
781: if (tree == null)
782: return code.mergeChains(falseJumps, code.branch(code
783: .negate(opcode)));
784: // we should proceed further in -Xjcov mode only
785: int startpc = code.curPc();
786: Chain c = code.mergeChains(falseJumps, code.branch(code
787: .negate(opcode)));
788: code.crt.put(tree, CRTable.CRT_BRANCH_FALSE, startpc, code
789: .curPc());
790: return c;
791: }
792:
793: CondItem negate() {
794: CondItem c = new CondItem(code.negate(opcode), falseJumps,
795: trueJumps);
796: c.tree = tree;
797: return c;
798: }
799:
800: int width() {
801: // a CondItem doesn't have a size on the stack per se.
802: throw new AssertionError();
803: }
804:
805: boolean isTrue() {
806: return falseJumps == null && opcode == goto_;
807: }
808:
809: boolean isFalse() {
810: return trueJumps == null && opcode == dontgoto;
811: }
812:
813: public String toString() {
814: return "cond(" + Code.mnem(opcode) + ")";
815: }
816: }
817: }
|