Tue, 29 Mar 2011 16:41:18 +0100
7027157: Project Coin: javac warnings for AutoCloseable.close throwing InterruptedException
Summary: javac should warn about use/declaration of AutoCloseable subclasses that can throw InterruptedException
Reviewed-by: jjg
1 /*
2 * Copyright (c) 1999, 2011, 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 an indexed expression.
114 * @param type The expression's type.
115 */
116 Item makeIndexedItem(Type type) {
117 return new IndexedItem(type);
118 }
120 /** Make an item representing a local variable.
121 * @param v The represented variable.
122 */
123 LocalItem makeLocalItem(VarSymbol v) {
124 return new LocalItem(v.erasure(types), v.adr);
125 }
127 /** Make an item representing a local anonymous variable.
128 * @param type The represented variable's type.
129 * @param reg The represented variable's register.
130 */
131 private LocalItem makeLocalItem(Type type, int reg) {
132 return new LocalItem(type, reg);
133 }
135 /** Make an item representing a static variable or method.
136 * @param member The represented symbol.
137 */
138 Item makeStaticItem(Symbol member) {
139 return new StaticItem(member);
140 }
142 /** Make an item representing an instance variable or method.
143 * @param member The represented symbol.
144 * @param nonvirtual Is the reference not virtual? (true for constructors
145 * and private members).
146 */
147 Item makeMemberItem(Symbol member, boolean nonvirtual) {
148 return new MemberItem(member, nonvirtual);
149 }
151 /** Make an item representing a literal.
152 * @param type The literal's type.
153 * @param value The literal's value.
154 */
155 Item makeImmediateItem(Type type, Object value) {
156 return new ImmediateItem(type, value);
157 }
159 /** Make an item representing an assignment expression.
160 * @param lhs The item representing the assignment's left hand side.
161 */
162 Item makeAssignItem(Item lhs) {
163 return new AssignItem(lhs);
164 }
166 /** Make an item representing a conditional or unconditional jump.
167 * @param opcode The jump's opcode.
168 * @param trueJumps A chain encomassing all jumps that can be taken
169 * if the condition evaluates to true.
170 * @param falseJumps A chain encomassing all jumps that can be taken
171 * if the condition evaluates to false.
172 */
173 CondItem makeCondItem(int opcode, Chain trueJumps, Chain falseJumps) {
174 return new CondItem(opcode, trueJumps, falseJumps);
175 }
177 /** Make an item representing a conditional or unconditional jump.
178 * @param opcode The jump's opcode.
179 */
180 CondItem makeCondItem(int opcode) {
181 return makeCondItem(opcode, null, null);
182 }
184 /** The base class of all items, which implements default behavior.
185 */
186 abstract class Item {
188 /** The type code of values represented by this item.
189 */
190 int typecode;
192 Item(int typecode) {
193 this.typecode = typecode;
194 }
196 /** Generate code to load this item onto stack.
197 */
198 Item load() {
199 throw new AssertionError();
200 }
202 /** Generate code to store top of stack into this item.
203 */
204 void store() {
205 throw new AssertionError("store unsupported: " + this);
206 }
208 /** Generate code to invoke method represented by this item.
209 */
210 Item invoke() {
211 throw new AssertionError(this);
212 }
214 /** Generate code to use this item twice.
215 */
216 void duplicate() {}
218 /** Generate code to avoid having to use this item.
219 */
220 void drop() {}
222 /** Generate code to stash a copy of top of stack - of typecode toscode -
223 * under this item.
224 */
225 void stash(int toscode) {
226 stackItem[toscode].duplicate();
227 }
229 /** Generate code to turn item into a testable condition.
230 */
231 CondItem mkCond() {
232 load();
233 return makeCondItem(ifne);
234 }
236 /** Generate code to coerce item to given type code.
237 * @param targetcode The type code to coerce to.
238 */
239 Item coerce(int targetcode) {
240 if (typecode == targetcode)
241 return this;
242 else {
243 load();
244 int typecode1 = Code.truncate(typecode);
245 int targetcode1 = Code.truncate(targetcode);
246 if (typecode1 != targetcode1) {
247 int offset = targetcode1 > typecode1 ? targetcode1 - 1
248 : targetcode1;
249 code.emitop0(i2l + typecode1 * 3 + offset);
250 }
251 if (targetcode != targetcode1) {
252 code.emitop0(int2byte + targetcode - BYTEcode);
253 }
254 return stackItem[targetcode];
255 }
256 }
258 /** Generate code to coerce item to given type.
259 * @param targettype The type to coerce to.
260 */
261 Item coerce(Type targettype) {
262 return coerce(Code.typecode(targettype));
263 }
265 /** Return the width of this item on stack as a number of words.
266 */
267 int width() {
268 return 0;
269 }
271 public abstract String toString();
272 }
274 /** An item representing a value on stack.
275 */
276 class StackItem extends Item {
278 StackItem(int typecode) {
279 super(typecode);
280 }
282 Item load() {
283 return this;
284 }
286 void duplicate() {
287 code.emitop0(width() == 2 ? dup2 : dup);
288 }
290 void drop() {
291 code.emitop0(width() == 2 ? pop2 : pop);
292 }
294 void stash(int toscode) {
295 code.emitop0(
296 (width() == 2 ? dup_x2 : dup_x1) + 3 * (Code.width(toscode) - 1));
297 }
299 int width() {
300 return Code.width(typecode);
301 }
303 public String toString() {
304 return "stack(" + typecodeNames[typecode] + ")";
305 }
306 }
308 /** An item representing an indexed expression.
309 */
310 class IndexedItem extends Item {
312 IndexedItem(Type type) {
313 super(Code.typecode(type));
314 }
316 Item load() {
317 code.emitop0(iaload + typecode);
318 return stackItem[typecode];
319 }
321 void store() {
322 code.emitop0(iastore + typecode);
323 }
325 void duplicate() {
326 code.emitop0(dup2);
327 }
329 void drop() {
330 code.emitop0(pop2);
331 }
333 void stash(int toscode) {
334 code.emitop0(dup_x2 + 3 * (Code.width(toscode) - 1));
335 }
337 int width() {
338 return 2;
339 }
341 public String toString() {
342 return "indexed(" + ByteCodes.typecodeNames[typecode] + ")";
343 }
344 }
346 /** An item representing `this' or `super'.
347 */
348 class SelfItem extends Item {
350 /** Flag which determines whether this item represents `this' or `super'.
351 */
352 boolean isSuper;
354 SelfItem(boolean isSuper) {
355 super(OBJECTcode);
356 this.isSuper = isSuper;
357 }
359 Item load() {
360 code.emitop0(aload_0);
361 return stackItem[typecode];
362 }
364 public String toString() {
365 return isSuper ? "super" : "this";
366 }
367 }
369 /** An item representing a local variable.
370 */
371 class LocalItem extends Item {
373 /** The variable's register.
374 */
375 int reg;
377 /** The variable's type.
378 */
379 Type type;
381 LocalItem(Type type, int reg) {
382 super(Code.typecode(type));
383 Assert.check(reg >= 0);
384 this.type = type;
385 this.reg = reg;
386 }
388 Item load() {
389 if (reg <= 3)
390 code.emitop0(iload_0 + Code.truncate(typecode) * 4 + reg);
391 else
392 code.emitop1w(iload + Code.truncate(typecode), reg);
393 return stackItem[typecode];
394 }
396 void store() {
397 if (reg <= 3)
398 code.emitop0(istore_0 + Code.truncate(typecode) * 4 + reg);
399 else
400 code.emitop1w(istore + Code.truncate(typecode), reg);
401 code.setDefined(reg);
402 }
404 void incr(int x) {
405 if (typecode == INTcode && x >= -32768 && x <= 32767) {
406 code.emitop1w(iinc, reg, x);
407 } else {
408 load();
409 if (x >= 0) {
410 makeImmediateItem(syms.intType, x).load();
411 code.emitop0(iadd);
412 } else {
413 makeImmediateItem(syms.intType, -x).load();
414 code.emitop0(isub);
415 }
416 makeStackItem(syms.intType).coerce(typecode);
417 store();
418 }
419 }
421 public String toString() {
422 return "localItem(type=" + type + "; reg=" + reg + ")";
423 }
424 }
426 /** An item representing a static variable or method.
427 */
428 class StaticItem extends Item {
430 /** The represented symbol.
431 */
432 Symbol member;
434 StaticItem(Symbol member) {
435 super(Code.typecode(member.erasure(types)));
436 this.member = member;
437 }
439 Item load() {
440 code.emitop2(getstatic, pool.put(member));
441 return stackItem[typecode];
442 }
444 void store() {
445 code.emitop2(putstatic, pool.put(member));
446 }
448 Item invoke() {
449 MethodType mtype = (MethodType)member.erasure(types);
450 int rescode = Code.typecode(mtype.restype);
451 code.emitInvokestatic(pool.put(member), mtype);
452 return stackItem[rescode];
453 }
455 public String toString() {
456 return "static(" + member + ")";
457 }
458 }
460 /** An item representing an instance variable or method.
461 */
462 class MemberItem extends Item {
464 /** The represented symbol.
465 */
466 Symbol member;
468 /** Flag that determines whether or not access is virtual.
469 */
470 boolean nonvirtual;
472 MemberItem(Symbol member, boolean nonvirtual) {
473 super(Code.typecode(member.erasure(types)));
474 this.member = member;
475 this.nonvirtual = nonvirtual;
476 }
478 Item load() {
479 code.emitop2(getfield, pool.put(member));
480 return stackItem[typecode];
481 }
483 void store() {
484 code.emitop2(putfield, pool.put(member));
485 }
487 Item invoke() {
488 MethodType mtype = (MethodType)member.externalType(types);
489 int rescode = Code.typecode(mtype.restype);
490 if ((member.owner.flags() & Flags.INTERFACE) != 0) {
491 code.emitInvokeinterface(pool.put(member), mtype);
492 } else if (nonvirtual) {
493 code.emitInvokespecial(pool.put(member), mtype);
494 } else {
495 code.emitInvokevirtual(pool.put(member), mtype);
496 }
497 return stackItem[rescode];
498 }
500 void duplicate() {
501 stackItem[OBJECTcode].duplicate();
502 }
504 void drop() {
505 stackItem[OBJECTcode].drop();
506 }
508 void stash(int toscode) {
509 stackItem[OBJECTcode].stash(toscode);
510 }
512 int width() {
513 return 1;
514 }
516 public String toString() {
517 return "member(" + member + (nonvirtual ? " nonvirtual)" : ")");
518 }
519 }
521 /** An item representing a literal.
522 */
523 class ImmediateItem extends Item {
525 /** The literal's value.
526 */
527 Object value;
529 ImmediateItem(Type type, Object value) {
530 super(Code.typecode(type));
531 this.value = value;
532 }
534 private void ldc() {
535 int idx = pool.put(value);
536 if (typecode == LONGcode || typecode == DOUBLEcode) {
537 code.emitop2(ldc2w, idx);
538 } else if (idx <= 255) {
539 code.emitop1(ldc1, idx);
540 } else {
541 code.emitop2(ldc2, idx);
542 }
543 }
545 Item load() {
546 switch (typecode) {
547 case INTcode: case BYTEcode: case SHORTcode: case CHARcode:
548 int ival = ((Number)value).intValue();
549 if (-1 <= ival && ival <= 5)
550 code.emitop0(iconst_0 + ival);
551 else if (Byte.MIN_VALUE <= ival && ival <= Byte.MAX_VALUE)
552 code.emitop1(bipush, ival);
553 else if (Short.MIN_VALUE <= ival && ival <= Short.MAX_VALUE)
554 code.emitop2(sipush, ival);
555 else
556 ldc();
557 break;
558 case LONGcode:
559 long lval = ((Number)value).longValue();
560 if (lval == 0 || lval == 1)
561 code.emitop0(lconst_0 + (int)lval);
562 else
563 ldc();
564 break;
565 case FLOATcode:
566 float fval = ((Number)value).floatValue();
567 if (isPosZero(fval) || fval == 1.0 || fval == 2.0)
568 code.emitop0(fconst_0 + (int)fval);
569 else {
570 ldc();
571 }
572 break;
573 case DOUBLEcode:
574 double dval = ((Number)value).doubleValue();
575 if (isPosZero(dval) || dval == 1.0)
576 code.emitop0(dconst_0 + (int)dval);
577 else
578 ldc();
579 break;
580 case OBJECTcode:
581 ldc();
582 break;
583 default:
584 Assert.error();
585 }
586 return stackItem[typecode];
587 }
588 //where
589 /** Return true iff float number is positive 0.
590 */
591 private boolean isPosZero(float x) {
592 return x == 0.0f && 1.0f / x > 0.0f;
593 }
594 /** Return true iff double number is positive 0.
595 */
596 private boolean isPosZero(double x) {
597 return x == 0.0d && 1.0d / x > 0.0d;
598 }
600 CondItem mkCond() {
601 int ival = ((Number)value).intValue();
602 return makeCondItem(ival != 0 ? goto_ : dontgoto);
603 }
605 Item coerce(int targetcode) {
606 if (typecode == targetcode) {
607 return this;
608 } else {
609 switch (targetcode) {
610 case INTcode:
611 if (Code.truncate(typecode) == INTcode)
612 return this;
613 else
614 return new ImmediateItem(
615 syms.intType,
616 ((Number)value).intValue());
617 case LONGcode:
618 return new ImmediateItem(
619 syms.longType,
620 ((Number)value).longValue());
621 case FLOATcode:
622 return new ImmediateItem(
623 syms.floatType,
624 ((Number)value).floatValue());
625 case DOUBLEcode:
626 return new ImmediateItem(
627 syms.doubleType,
628 ((Number)value).doubleValue());
629 case BYTEcode:
630 return new ImmediateItem(
631 syms.byteType,
632 (int)(byte)((Number)value).intValue());
633 case CHARcode:
634 return new ImmediateItem(
635 syms.charType,
636 (int)(char)((Number)value).intValue());
637 case SHORTcode:
638 return new ImmediateItem(
639 syms.shortType,
640 (int)(short)((Number)value).intValue());
641 default:
642 return super.coerce(targetcode);
643 }
644 }
645 }
647 public String toString() {
648 return "immediate(" + value + ")";
649 }
650 }
652 /** An item representing an assignment expressions.
653 */
654 class AssignItem extends Item {
656 /** The item representing the assignment's left hand side.
657 */
658 Item lhs;
660 AssignItem(Item lhs) {
661 super(lhs.typecode);
662 this.lhs = lhs;
663 }
665 Item load() {
666 lhs.stash(typecode);
667 lhs.store();
668 return stackItem[typecode];
669 }
671 void duplicate() {
672 load().duplicate();
673 }
675 void drop() {
676 lhs.store();
677 }
679 void stash(int toscode) {
680 Assert.error();
681 }
683 int width() {
684 return lhs.width() + Code.width(typecode);
685 }
687 public String toString() {
688 return "assign(lhs = " + lhs + ")";
689 }
690 }
692 /** An item representing a conditional or unconditional jump.
693 */
694 class CondItem extends Item {
696 /** A chain encomassing all jumps that can be taken
697 * if the condition evaluates to true.
698 */
699 Chain trueJumps;
701 /** A chain encomassing all jumps that can be taken
702 * if the condition evaluates to false.
703 */
704 Chain falseJumps;
706 /** The jump's opcode.
707 */
708 int opcode;
710 /*
711 * An abstract syntax tree of this item. It is needed
712 * for branch entries in 'CharacterRangeTable' attribute.
713 */
714 JCTree tree;
716 CondItem(int opcode, Chain truejumps, Chain falsejumps) {
717 super(BYTEcode);
718 this.opcode = opcode;
719 this.trueJumps = truejumps;
720 this.falseJumps = falsejumps;
721 }
723 Item load() {
724 Chain trueChain = null;
725 Chain falseChain = jumpFalse();
726 if (!isFalse()) {
727 code.resolve(trueJumps);
728 code.emitop0(iconst_1);
729 trueChain = code.branch(goto_);
730 }
731 if (falseChain != null) {
732 code.resolve(falseChain);
733 code.emitop0(iconst_0);
734 }
735 code.resolve(trueChain);
736 return stackItem[typecode];
737 }
739 void duplicate() {
740 load().duplicate();
741 }
743 void drop() {
744 load().drop();
745 }
747 void stash(int toscode) {
748 Assert.error();
749 }
751 CondItem mkCond() {
752 return this;
753 }
755 Chain jumpTrue() {
756 if (tree == null) return Code.mergeChains(trueJumps, code.branch(opcode));
757 // we should proceed further in -Xjcov mode only
758 int startpc = code.curPc();
759 Chain c = Code.mergeChains(trueJumps, code.branch(opcode));
760 code.crt.put(tree, CRTable.CRT_BRANCH_TRUE, startpc, code.curPc());
761 return c;
762 }
764 Chain jumpFalse() {
765 if (tree == null) return Code.mergeChains(falseJumps, code.branch(Code.negate(opcode)));
766 // we should proceed further in -Xjcov mode only
767 int startpc = code.curPc();
768 Chain c = Code.mergeChains(falseJumps, code.branch(Code.negate(opcode)));
769 code.crt.put(tree, CRTable.CRT_BRANCH_FALSE, startpc, code.curPc());
770 return c;
771 }
773 CondItem negate() {
774 CondItem c = new CondItem(Code.negate(opcode), falseJumps, trueJumps);
775 c.tree = tree;
776 return c;
777 }
779 int width() {
780 // a CondItem doesn't have a size on the stack per se.
781 throw new AssertionError();
782 }
784 boolean isTrue() {
785 return falseJumps == null && opcode == goto_;
786 }
788 boolean isFalse() {
789 return trueJumps == null && opcode == dontgoto;
790 }
792 public String toString() {
793 return "cond(" + Code.mnem(opcode) + ")";
794 }
795 }
796 }