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 | */ |
25 | |
26 | package com.sun.tools.javac.jvm; |
27 | |
28 | import com.sun.tools.javac.util.*; |
29 | import com.sun.tools.javac.code.*; |
30 | |
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; |
35 | |
36 | import static com.sun.tools.javac.code.TypeTags.*; |
37 | import static com.sun.tools.javac.jvm.ByteCodes.*; |
38 | |
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 { |
54 | |
55 | /** The current constant pool. |
56 | */ |
57 | Pool pool; |
58 | |
59 | /** The current code buffer. |
60 | */ |
61 | Code code; |
62 | |
63 | /** The current symbol table. |
64 | */ |
65 | Symtab syms; |
66 | |
67 | /** Type utilities. */ |
68 | Types types; |
69 | |
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]; |
76 | |
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 | } |
90 | |
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 | } |
101 | |
102 | /** Make an item representing `super'. |
103 | */ |
104 | Item makeSuperItem() { |
105 | return superItem; |
106 | } |
107 | |
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 | } |
114 | |
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 | } |
121 | |
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 | } |
128 | |
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 | } |
136 | |
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 | } |
143 | |
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 | } |
152 | |
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 | } |
160 | |
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 | } |
167 | |
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 | } |
178 | |
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 | } |
185 | |
186 | /** The base class of all items, which implements default behavior. |
187 | */ |
188 | abstract class Item { |
189 | |
190 | /** The type code of values represented by this item. |
191 | */ |
192 | int typecode; |
193 | |
194 | Item(int typecode) { |
195 | this.typecode = typecode; |
196 | } |
197 | |
198 | /** Generate code to load this item onto stack. |
199 | */ |
200 | Item load() { |
201 | throw new AssertionError(); |
202 | } |
203 | |
204 | /** Generate code to store top of stack into this item. |
205 | */ |
206 | void store() { |
207 | throw new AssertionError("store unsupported: " + this); |
208 | } |
209 | |
210 | /** Generate code to invoke method represented by this item. |
211 | */ |
212 | Item invoke() { |
213 | throw new AssertionError(this); |
214 | } |
215 | |
216 | /** Generate code to use this item twice. |
217 | */ |
218 | void duplicate() {} |
219 | |
220 | /** Generate code to avoid having to use this item. |
221 | */ |
222 | void drop() {} |
223 | |
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 | } |
230 | |
231 | /** Generate code to turn item into a testable condition. |
232 | */ |
233 | CondItem mkCond() { |
234 | load(); |
235 | return makeCondItem(ifne); |
236 | } |
237 | |
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 | } |
259 | |
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 | } |
266 | |
267 | /** Return the width of this item on stack as a number of words. |
268 | */ |
269 | int width() { |
270 | return 0; |
271 | } |
272 | |
273 | public abstract String toString(); |
274 | } |
275 | |
276 | /** An item representing a value on stack. |
277 | */ |
278 | class StackItem extends Item { |
279 | |
280 | StackItem(int typecode) { |
281 | super(typecode); |
282 | } |
283 | |
284 | Item load() { |
285 | return this; |
286 | } |
287 | |
288 | void duplicate() { |
289 | code.emitop0(width() == 2 ? dup2 : dup); |
290 | } |
291 | |
292 | void drop() { |
293 | code.emitop0(width() == 2 ? pop2 : pop); |
294 | } |
295 | |
296 | void stash(int toscode) { |
297 | code.emitop0( |
298 | (width() == 2 ? dup_x2 : dup_x1) + 3 * (Code.width(toscode) - 1)); |
299 | } |
300 | |
301 | int width() { |
302 | return Code.width(typecode); |
303 | } |
304 | |
305 | public String toString() { |
306 | return "stack(" + typecodeNames[typecode] + ")"; |
307 | } |
308 | } |
309 | |
310 | /** An item representing an indexed expression. |
311 | */ |
312 | class IndexedItem extends Item { |
313 | |
314 | IndexedItem(Type type) { |
315 | super(Code.typecode(type)); |
316 | } |
317 | |
318 | Item load() { |
319 | code.emitop0(iaload + typecode); |
320 | return stackItem[typecode]; |
321 | } |
322 | |
323 | void store() { |
324 | code.emitop0(iastore + typecode); |
325 | } |
326 | |
327 | void duplicate() { |
328 | code.emitop0(dup2); |
329 | } |
330 | |
331 | void drop() { |
332 | code.emitop0(pop2); |
333 | } |
334 | |
335 | void stash(int toscode) { |
336 | code.emitop0(dup_x2 + 3 * (Code.width(toscode) - 1)); |
337 | } |
338 | |
339 | int width() { |
340 | return 2; |
341 | } |
342 | |
343 | public String toString() { |
344 | return "indexed(" + ByteCodes.typecodeNames[typecode] + ")"; |
345 | } |
346 | } |
347 | |
348 | /** An item representing `this' or `super'. |
349 | */ |
350 | class SelfItem extends Item { |
351 | |
352 | /** Flag which determines whether this item represents `this' or `super'. |
353 | */ |
354 | boolean isSuper; |
355 | |
356 | SelfItem(boolean isSuper) { |
357 | super(OBJECTcode); |
358 | this.isSuper = isSuper; |
359 | } |
360 | |
361 | Item load() { |
362 | code.emitop0(aload_0); |
363 | return stackItem[typecode]; |
364 | } |
365 | |
366 | public String toString() { |
367 | return isSuper ? "super" : "this"; |
368 | } |
369 | } |
370 | |
371 | /** An item representing a local variable. |
372 | */ |
373 | class LocalItem extends Item { |
374 | |
375 | /** The variable's register. |
376 | */ |
377 | int reg; |
378 | |
379 | /** The variable's type. |
380 | */ |
381 | Type type; |
382 | |
383 | LocalItem(Type type, int reg) { |
384 | super(Code.typecode(type)); |
385 | assert reg >= 0; |
386 | this.type = type; |
387 | this.reg = reg; |
388 | } |
389 | |
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 | } |
397 | |
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 | } |
405 | |
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 | } |
422 | |
423 | public String toString() { |
424 | return "localItem(type=" + type + "; reg=" + reg + ")"; |
425 | } |
426 | } |
427 | |
428 | /** An item representing a static variable or method. |
429 | */ |
430 | class StaticItem extends Item { |
431 | |
432 | /** The represented symbol. |
433 | */ |
434 | Symbol member; |
435 | |
436 | StaticItem(Symbol member) { |
437 | super(Code.typecode(member.erasure(types))); |
438 | this.member = member; |
439 | } |
440 | |
441 | Item load() { |
442 | code.emitop2(getstatic, pool.put(member)); |
443 | return stackItem[typecode]; |
444 | } |
445 | |
446 | void store() { |
447 | code.emitop2(putstatic, pool.put(member)); |
448 | } |
449 | |
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 | } |
458 | |
459 | public String toString() { |
460 | return "static(" + member + ")"; |
461 | } |
462 | } |
463 | |
464 | /** An item representing an instance variable or method. |
465 | */ |
466 | class MemberItem extends Item { |
467 | |
468 | /** The represented symbol. |
469 | */ |
470 | Symbol member; |
471 | |
472 | /** Flag that determines whether or not access is virtual. |
473 | */ |
474 | boolean nonvirtual; |
475 | |
476 | MemberItem(Symbol member, boolean nonvirtual) { |
477 | super(Code.typecode(member.erasure(types))); |
478 | this.member = member; |
479 | this.nonvirtual = nonvirtual; |
480 | } |
481 | |
482 | Item load() { |
483 | code.emitop2(getfield, pool.put(member)); |
484 | return stackItem[typecode]; |
485 | } |
486 | |
487 | void store() { |
488 | code.emitop2(putfield, pool.put(member)); |
489 | } |
490 | |
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 | } |
503 | |
504 | void duplicate() { |
505 | stackItem[OBJECTcode].duplicate(); |
506 | } |
507 | |
508 | void drop() { |
509 | stackItem[OBJECTcode].drop(); |
510 | } |
511 | |
512 | void stash(int toscode) { |
513 | stackItem[OBJECTcode].stash(toscode); |
514 | } |
515 | |
516 | int width() { |
517 | return 1; |
518 | } |
519 | |
520 | public String toString() { |
521 | return "member(" + member + (nonvirtual ? " nonvirtual)" : ")"); |
522 | } |
523 | } |
524 | |
525 | /** An item representing a literal. |
526 | */ |
527 | class ImmediateItem extends Item { |
528 | |
529 | /** The literal's value. |
530 | */ |
531 | Object value; |
532 | |
533 | ImmediateItem(Type type, Object value) { |
534 | super(Code.typecode(type)); |
535 | this.value = value; |
536 | } |
537 | |
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 | } |
548 | |
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 | } |
603 | |
604 | CondItem mkCond() { |
605 | int ival = ((Number)value).intValue(); |
606 | return makeCondItem(ival != 0 ? goto_ : dontgoto); |
607 | } |
608 | |
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 | } |
650 | |
651 | public String toString() { |
652 | return "immediate(" + value + ")"; |
653 | } |
654 | } |
655 | |
656 | /** An item representing an assignment expressions. |
657 | */ |
658 | class AssignItem extends Item { |
659 | |
660 | /** The item representing the assignment's left hand side. |
661 | */ |
662 | Item lhs; |
663 | |
664 | AssignItem(Item lhs) { |
665 | super(lhs.typecode); |
666 | this.lhs = lhs; |
667 | } |
668 | |
669 | Item load() { |
670 | lhs.stash(typecode); |
671 | lhs.store(); |
672 | return stackItem[typecode]; |
673 | } |
674 | |
675 | void duplicate() { |
676 | load().duplicate(); |
677 | } |
678 | |
679 | void drop() { |
680 | lhs.store(); |
681 | } |
682 | |
683 | void stash(int toscode) { |
684 | assert false; |
685 | } |
686 | |
687 | int width() { |
688 | return lhs.width() + Code.width(typecode); |
689 | } |
690 | |
691 | public String toString() { |
692 | return "assign(lhs = " + lhs + ")"; |
693 | } |
694 | } |
695 | |
696 | /** An item representing a conditional or unconditional jump. |
697 | */ |
698 | class CondItem extends Item { |
699 | |
700 | /** A chain encomassing all jumps that can be taken |
701 | * if the condition evaluates to true. |
702 | */ |
703 | Chain trueJumps; |
704 | |
705 | /** A chain encomassing all jumps that can be taken |
706 | * if the condition evaluates to false. |
707 | */ |
708 | Chain falseJumps; |
709 | |
710 | /** The jump's opcode. |
711 | */ |
712 | int opcode; |
713 | |
714 | /* |
715 | * An abstract syntax tree of this item. It is needed |
716 | * for branch entries in 'CharacterRangeTable' attribute. |
717 | */ |
718 | JCTree tree; |
719 | |
720 | CondItem(int opcode, Chain truejumps, Chain falsejumps) { |
721 | super(BYTEcode); |
722 | this.opcode = opcode; |
723 | this.trueJumps = truejumps; |
724 | this.falseJumps = falsejumps; |
725 | } |
726 | |
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 | } |
742 | |
743 | void duplicate() { |
744 | load().duplicate(); |
745 | } |
746 | |
747 | void drop() { |
748 | load().drop(); |
749 | } |
750 | |
751 | void stash(int toscode) { |
752 | assert false; |
753 | } |
754 | |
755 | CondItem mkCond() { |
756 | return this; |
757 | } |
758 | |
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 | } |
767 | |
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 | } |
776 | |
777 | CondItem negate() { |
778 | CondItem c = new CondItem(code.negate(opcode), falseJumps, trueJumps); |
779 | c.tree = tree; |
780 | return c; |
781 | } |
782 | |
783 | int width() { |
784 | // a CondItem doesn't have a size on the stack per se. |
785 | throw new AssertionError(); |
786 | } |
787 | |
788 | boolean isTrue() { |
789 | return falseJumps == null && opcode == goto_; |
790 | } |
791 | |
792 | boolean isFalse() { |
793 | return trueJumps == null && opcode == dontgoto; |
794 | } |
795 | |
796 | public String toString() { |
797 | return "cond(" + Code.mnem(opcode) + ")"; |
798 | } |
799 | } |
800 | } |