Mon, 25 Mar 2013 16:55:14 -0700
8010521: jdk8 l10n resource file translation update 2
Reviewed-by: naoto, yhuang
1 /*
2 * Copyright (c) 1999, 2012, 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 if (idx <= 255) {
575 code.emitop1(ldc1, idx);
576 } else {
577 code.emitop2(ldc2, idx);
578 }
579 }
581 Item load() {
582 switch (typecode) {
583 case INTcode: case BYTEcode: case SHORTcode: case CHARcode:
584 int ival = ((Number)value).intValue();
585 if (-1 <= ival && ival <= 5)
586 code.emitop0(iconst_0 + ival);
587 else if (Byte.MIN_VALUE <= ival && ival <= Byte.MAX_VALUE)
588 code.emitop1(bipush, ival);
589 else if (Short.MIN_VALUE <= ival && ival <= Short.MAX_VALUE)
590 code.emitop2(sipush, ival);
591 else
592 ldc();
593 break;
594 case LONGcode:
595 long lval = ((Number)value).longValue();
596 if (lval == 0 || lval == 1)
597 code.emitop0(lconst_0 + (int)lval);
598 else
599 ldc();
600 break;
601 case FLOATcode:
602 float fval = ((Number)value).floatValue();
603 if (isPosZero(fval) || fval == 1.0 || fval == 2.0)
604 code.emitop0(fconst_0 + (int)fval);
605 else {
606 ldc();
607 }
608 break;
609 case DOUBLEcode:
610 double dval = ((Number)value).doubleValue();
611 if (isPosZero(dval) || dval == 1.0)
612 code.emitop0(dconst_0 + (int)dval);
613 else
614 ldc();
615 break;
616 case OBJECTcode:
617 ldc();
618 break;
619 default:
620 Assert.error();
621 }
622 return stackItem[typecode];
623 }
624 //where
625 /** Return true iff float number is positive 0.
626 */
627 private boolean isPosZero(float x) {
628 return x == 0.0f && 1.0f / x > 0.0f;
629 }
630 /** Return true iff double number is positive 0.
631 */
632 private boolean isPosZero(double x) {
633 return x == 0.0d && 1.0d / x > 0.0d;
634 }
636 CondItem mkCond() {
637 int ival = ((Number)value).intValue();
638 return makeCondItem(ival != 0 ? goto_ : dontgoto);
639 }
641 Item coerce(int targetcode) {
642 if (typecode == targetcode) {
643 return this;
644 } else {
645 switch (targetcode) {
646 case INTcode:
647 if (Code.truncate(typecode) == INTcode)
648 return this;
649 else
650 return new ImmediateItem(
651 syms.intType,
652 ((Number)value).intValue());
653 case LONGcode:
654 return new ImmediateItem(
655 syms.longType,
656 ((Number)value).longValue());
657 case FLOATcode:
658 return new ImmediateItem(
659 syms.floatType,
660 ((Number)value).floatValue());
661 case DOUBLEcode:
662 return new ImmediateItem(
663 syms.doubleType,
664 ((Number)value).doubleValue());
665 case BYTEcode:
666 return new ImmediateItem(
667 syms.byteType,
668 (int)(byte)((Number)value).intValue());
669 case CHARcode:
670 return new ImmediateItem(
671 syms.charType,
672 (int)(char)((Number)value).intValue());
673 case SHORTcode:
674 return new ImmediateItem(
675 syms.shortType,
676 (int)(short)((Number)value).intValue());
677 default:
678 return super.coerce(targetcode);
679 }
680 }
681 }
683 public String toString() {
684 return "immediate(" + value + ")";
685 }
686 }
688 /** An item representing an assignment expressions.
689 */
690 class AssignItem extends Item {
692 /** The item representing the assignment's left hand side.
693 */
694 Item lhs;
696 AssignItem(Item lhs) {
697 super(lhs.typecode);
698 this.lhs = lhs;
699 }
701 Item load() {
702 lhs.stash(typecode);
703 lhs.store();
704 return stackItem[typecode];
705 }
707 void duplicate() {
708 load().duplicate();
709 }
711 void drop() {
712 lhs.store();
713 }
715 void stash(int toscode) {
716 Assert.error();
717 }
719 int width() {
720 return lhs.width() + Code.width(typecode);
721 }
723 public String toString() {
724 return "assign(lhs = " + lhs + ")";
725 }
726 }
728 /** An item representing a conditional or unconditional jump.
729 */
730 class CondItem extends Item {
732 /** A chain encomassing all jumps that can be taken
733 * if the condition evaluates to true.
734 */
735 Chain trueJumps;
737 /** A chain encomassing all jumps that can be taken
738 * if the condition evaluates to false.
739 */
740 Chain falseJumps;
742 /** The jump's opcode.
743 */
744 int opcode;
746 /*
747 * An abstract syntax tree of this item. It is needed
748 * for branch entries in 'CharacterRangeTable' attribute.
749 */
750 JCTree tree;
752 CondItem(int opcode, Chain truejumps, Chain falsejumps) {
753 super(BYTEcode);
754 this.opcode = opcode;
755 this.trueJumps = truejumps;
756 this.falseJumps = falsejumps;
757 }
759 Item load() {
760 Chain trueChain = null;
761 Chain falseChain = jumpFalse();
762 if (!isFalse()) {
763 code.resolve(trueJumps);
764 code.emitop0(iconst_1);
765 trueChain = code.branch(goto_);
766 }
767 if (falseChain != null) {
768 code.resolve(falseChain);
769 code.emitop0(iconst_0);
770 }
771 code.resolve(trueChain);
772 return stackItem[typecode];
773 }
775 void duplicate() {
776 load().duplicate();
777 }
779 void drop() {
780 load().drop();
781 }
783 void stash(int toscode) {
784 Assert.error();
785 }
787 CondItem mkCond() {
788 return this;
789 }
791 Chain jumpTrue() {
792 if (tree == null) return Code.mergeChains(trueJumps, code.branch(opcode));
793 // we should proceed further in -Xjcov mode only
794 int startpc = code.curPc();
795 Chain c = Code.mergeChains(trueJumps, code.branch(opcode));
796 code.crt.put(tree, CRTable.CRT_BRANCH_TRUE, startpc, code.curPc());
797 return c;
798 }
800 Chain jumpFalse() {
801 if (tree == null) return Code.mergeChains(falseJumps, code.branch(Code.negate(opcode)));
802 // we should proceed further in -Xjcov mode only
803 int startpc = code.curPc();
804 Chain c = Code.mergeChains(falseJumps, code.branch(Code.negate(opcode)));
805 code.crt.put(tree, CRTable.CRT_BRANCH_FALSE, startpc, code.curPc());
806 return c;
807 }
809 CondItem negate() {
810 CondItem c = new CondItem(Code.negate(opcode), falseJumps, trueJumps);
811 c.tree = tree;
812 return c;
813 }
815 int width() {
816 // a CondItem doesn't have a size on the stack per se.
817 throw new AssertionError();
818 }
820 boolean isTrue() {
821 return falseJumps == null && opcode == goto_;
822 }
824 boolean isFalse() {
825 return trueJumps == null && opcode == dontgoto;
826 }
828 public String toString() {
829 return "cond(" + Code.mnem(opcode) + ")";
830 }
831 }
832 }