|
1 /* |
|
2 * Copyright (c) 1999, 2013, 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 */ |
|
25 |
|
26 package com.sun.tools.javac.jvm; |
|
27 |
|
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; |
|
34 |
|
35 import static com.sun.tools.javac.jvm.ByteCodes.*; |
|
36 |
|
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 { |
|
52 |
|
53 /** The current constant pool. |
|
54 */ |
|
55 Pool pool; |
|
56 |
|
57 /** The current code buffer. |
|
58 */ |
|
59 Code code; |
|
60 |
|
61 /** The current symbol table. |
|
62 */ |
|
63 Symtab syms; |
|
64 |
|
65 /** Type utilities. */ |
|
66 Types types; |
|
67 |
|
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]; |
|
74 |
|
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 } |
|
88 |
|
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 } |
|
99 |
|
100 /** Make an item representing `super'. |
|
101 */ |
|
102 Item makeSuperItem() { |
|
103 return superItem; |
|
104 } |
|
105 |
|
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 } |
|
112 |
|
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 } |
|
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 /** Generate code to avoid having to use this item. |
|
226 */ |
|
227 void drop() {} |
|
228 |
|
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 } |
|
235 |
|
236 /** Generate code to turn item into a testable condition. |
|
237 */ |
|
238 CondItem mkCond() { |
|
239 load(); |
|
240 return makeCondItem(ifne); |
|
241 } |
|
242 |
|
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 } |
|
264 |
|
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 } |
|
271 |
|
272 /** Return the width of this item on stack as a number of words. |
|
273 */ |
|
274 int width() { |
|
275 return 0; |
|
276 } |
|
277 |
|
278 public abstract String toString(); |
|
279 } |
|
280 |
|
281 /** An item representing a value on stack. |
|
282 */ |
|
283 class StackItem extends Item { |
|
284 |
|
285 StackItem(int typecode) { |
|
286 super(typecode); |
|
287 } |
|
288 |
|
289 Item load() { |
|
290 return this; |
|
291 } |
|
292 |
|
293 void duplicate() { |
|
294 code.emitop0(width() == 2 ? dup2 : dup); |
|
295 } |
|
296 |
|
297 void drop() { |
|
298 code.emitop0(width() == 2 ? pop2 : pop); |
|
299 } |
|
300 |
|
301 void stash(int toscode) { |
|
302 code.emitop0( |
|
303 (width() == 2 ? dup_x2 : dup_x1) + 3 * (Code.width(toscode) - 1)); |
|
304 } |
|
305 |
|
306 int width() { |
|
307 return Code.width(typecode); |
|
308 } |
|
309 |
|
310 public String toString() { |
|
311 return "stack(" + typecodeNames[typecode] + ")"; |
|
312 } |
|
313 } |
|
314 |
|
315 /** An item representing an indexed expression. |
|
316 */ |
|
317 class IndexedItem extends Item { |
|
318 |
|
319 IndexedItem(Type type) { |
|
320 super(Code.typecode(type)); |
|
321 } |
|
322 |
|
323 Item load() { |
|
324 code.emitop0(iaload + typecode); |
|
325 return stackItem[typecode]; |
|
326 } |
|
327 |
|
328 void store() { |
|
329 code.emitop0(iastore + typecode); |
|
330 } |
|
331 |
|
332 void duplicate() { |
|
333 code.emitop0(dup2); |
|
334 } |
|
335 |
|
336 void drop() { |
|
337 code.emitop0(pop2); |
|
338 } |
|
339 |
|
340 void stash(int toscode) { |
|
341 code.emitop0(dup_x2 + 3 * (Code.width(toscode) - 1)); |
|
342 } |
|
343 |
|
344 int width() { |
|
345 return 2; |
|
346 } |
|
347 |
|
348 public String toString() { |
|
349 return "indexed(" + ByteCodes.typecodeNames[typecode] + ")"; |
|
350 } |
|
351 } |
|
352 |
|
353 /** An item representing `this' or `super'. |
|
354 */ |
|
355 class SelfItem extends Item { |
|
356 |
|
357 /** Flag which determines whether this item represents `this' or `super'. |
|
358 */ |
|
359 boolean isSuper; |
|
360 |
|
361 SelfItem(boolean isSuper) { |
|
362 super(OBJECTcode); |
|
363 this.isSuper = isSuper; |
|
364 } |
|
365 |
|
366 Item load() { |
|
367 code.emitop0(aload_0); |
|
368 return stackItem[typecode]; |
|
369 } |
|
370 |
|
371 public String toString() { |
|
372 return isSuper ? "super" : "this"; |
|
373 } |
|
374 } |
|
375 |
|
376 /** An item representing a local variable. |
|
377 */ |
|
378 class LocalItem extends Item { |
|
379 |
|
380 /** The variable's register. |
|
381 */ |
|
382 int reg; |
|
383 |
|
384 /** The variable's type. |
|
385 */ |
|
386 Type type; |
|
387 |
|
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 } |
|
394 |
|
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 } |
|
402 |
|
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 } |
|
410 |
|
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 } |
|
427 |
|
428 public String toString() { |
|
429 return "localItem(type=" + type + "; reg=" + reg + ")"; |
|
430 } |
|
431 } |
|
432 |
|
433 /** An item representing a static variable or method. |
|
434 */ |
|
435 class StaticItem extends Item { |
|
436 |
|
437 /** The represented symbol. |
|
438 */ |
|
439 Symbol member; |
|
440 |
|
441 StaticItem(Symbol member) { |
|
442 super(Code.typecode(member.erasure(types))); |
|
443 this.member = member; |
|
444 } |
|
445 |
|
446 Item load() { |
|
447 code.emitop2(getstatic, pool.put(member)); |
|
448 return stackItem[typecode]; |
|
449 } |
|
450 |
|
451 void store() { |
|
452 code.emitop2(putstatic, pool.put(member)); |
|
453 } |
|
454 |
|
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 } |
|
461 |
|
462 public String toString() { |
|
463 return "static(" + member + ")"; |
|
464 } |
|
465 } |
|
466 |
|
467 /** An item representing a dynamic call site. |
|
468 */ |
|
469 class DynamicItem extends StaticItem { |
|
470 DynamicItem(Symbol member) { |
|
471 super(member); |
|
472 } |
|
473 |
|
474 Item load() { |
|
475 assert false; |
|
476 return null; |
|
477 } |
|
478 |
|
479 void store() { |
|
480 assert false; |
|
481 } |
|
482 |
|
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 } |
|
490 |
|
491 public String toString() { |
|
492 return "dynamic(" + member + ")"; |
|
493 } |
|
494 } |
|
495 |
|
496 /** An item representing an instance variable or method. |
|
497 */ |
|
498 class MemberItem extends Item { |
|
499 |
|
500 /** The represented symbol. |
|
501 */ |
|
502 Symbol member; |
|
503 |
|
504 /** Flag that determines whether or not access is virtual. |
|
505 */ |
|
506 boolean nonvirtual; |
|
507 |
|
508 MemberItem(Symbol member, boolean nonvirtual) { |
|
509 super(Code.typecode(member.erasure(types))); |
|
510 this.member = member; |
|
511 this.nonvirtual = nonvirtual; |
|
512 } |
|
513 |
|
514 Item load() { |
|
515 code.emitop2(getfield, pool.put(member)); |
|
516 return stackItem[typecode]; |
|
517 } |
|
518 |
|
519 void store() { |
|
520 code.emitop2(putfield, pool.put(member)); |
|
521 } |
|
522 |
|
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 } |
|
535 |
|
536 void duplicate() { |
|
537 stackItem[OBJECTcode].duplicate(); |
|
538 } |
|
539 |
|
540 void drop() { |
|
541 stackItem[OBJECTcode].drop(); |
|
542 } |
|
543 |
|
544 void stash(int toscode) { |
|
545 stackItem[OBJECTcode].stash(toscode); |
|
546 } |
|
547 |
|
548 int width() { |
|
549 return 1; |
|
550 } |
|
551 |
|
552 public String toString() { |
|
553 return "member(" + member + (nonvirtual ? " nonvirtual)" : ")"); |
|
554 } |
|
555 } |
|
556 |
|
557 /** An item representing a literal. |
|
558 */ |
|
559 class ImmediateItem extends Item { |
|
560 |
|
561 /** The literal's value. |
|
562 */ |
|
563 Object value; |
|
564 |
|
565 ImmediateItem(Type type, Object value) { |
|
566 super(Code.typecode(type)); |
|
567 this.value = value; |
|
568 } |
|
569 |
|
570 private void ldc() { |
|
571 int idx = pool.put(value); |
|
572 if (typecode == LONGcode || typecode == DOUBLEcode) { |
|
573 code.emitop2(ldc2w, idx); |
|
574 } else { |
|
575 code.emitLdc(idx); |
|
576 } |
|
577 } |
|
578 |
|
579 Item load() { |
|
580 switch (typecode) { |
|
581 case INTcode: case BYTEcode: case SHORTcode: case CHARcode: |
|
582 int ival = ((Number)value).intValue(); |
|
583 if (-1 <= ival && ival <= 5) |
|
584 code.emitop0(iconst_0 + ival); |
|
585 else if (Byte.MIN_VALUE <= ival && ival <= Byte.MAX_VALUE) |
|
586 code.emitop1(bipush, ival); |
|
587 else if (Short.MIN_VALUE <= ival && ival <= Short.MAX_VALUE) |
|
588 code.emitop2(sipush, ival); |
|
589 else |
|
590 ldc(); |
|
591 break; |
|
592 case LONGcode: |
|
593 long lval = ((Number)value).longValue(); |
|
594 if (lval == 0 || lval == 1) |
|
595 code.emitop0(lconst_0 + (int)lval); |
|
596 else |
|
597 ldc(); |
|
598 break; |
|
599 case FLOATcode: |
|
600 float fval = ((Number)value).floatValue(); |
|
601 if (isPosZero(fval) || fval == 1.0 || fval == 2.0) |
|
602 code.emitop0(fconst_0 + (int)fval); |
|
603 else { |
|
604 ldc(); |
|
605 } |
|
606 break; |
|
607 case DOUBLEcode: |
|
608 double dval = ((Number)value).doubleValue(); |
|
609 if (isPosZero(dval) || dval == 1.0) |
|
610 code.emitop0(dconst_0 + (int)dval); |
|
611 else |
|
612 ldc(); |
|
613 break; |
|
614 case OBJECTcode: |
|
615 ldc(); |
|
616 break; |
|
617 default: |
|
618 Assert.error(); |
|
619 } |
|
620 return stackItem[typecode]; |
|
621 } |
|
622 //where |
|
623 /** Return true iff float number is positive 0. |
|
624 */ |
|
625 private boolean isPosZero(float x) { |
|
626 return x == 0.0f && 1.0f / x > 0.0f; |
|
627 } |
|
628 /** Return true iff double number is positive 0. |
|
629 */ |
|
630 private boolean isPosZero(double x) { |
|
631 return x == 0.0d && 1.0d / x > 0.0d; |
|
632 } |
|
633 |
|
634 CondItem mkCond() { |
|
635 int ival = ((Number)value).intValue(); |
|
636 return makeCondItem(ival != 0 ? goto_ : dontgoto); |
|
637 } |
|
638 |
|
639 Item coerce(int targetcode) { |
|
640 if (typecode == targetcode) { |
|
641 return this; |
|
642 } else { |
|
643 switch (targetcode) { |
|
644 case INTcode: |
|
645 if (Code.truncate(typecode) == INTcode) |
|
646 return this; |
|
647 else |
|
648 return new ImmediateItem( |
|
649 syms.intType, |
|
650 ((Number)value).intValue()); |
|
651 case LONGcode: |
|
652 return new ImmediateItem( |
|
653 syms.longType, |
|
654 ((Number)value).longValue()); |
|
655 case FLOATcode: |
|
656 return new ImmediateItem( |
|
657 syms.floatType, |
|
658 ((Number)value).floatValue()); |
|
659 case DOUBLEcode: |
|
660 return new ImmediateItem( |
|
661 syms.doubleType, |
|
662 ((Number)value).doubleValue()); |
|
663 case BYTEcode: |
|
664 return new ImmediateItem( |
|
665 syms.byteType, |
|
666 (int)(byte)((Number)value).intValue()); |
|
667 case CHARcode: |
|
668 return new ImmediateItem( |
|
669 syms.charType, |
|
670 (int)(char)((Number)value).intValue()); |
|
671 case SHORTcode: |
|
672 return new ImmediateItem( |
|
673 syms.shortType, |
|
674 (int)(short)((Number)value).intValue()); |
|
675 default: |
|
676 return super.coerce(targetcode); |
|
677 } |
|
678 } |
|
679 } |
|
680 |
|
681 public String toString() { |
|
682 return "immediate(" + value + ")"; |
|
683 } |
|
684 } |
|
685 |
|
686 /** An item representing an assignment expressions. |
|
687 */ |
|
688 class AssignItem extends Item { |
|
689 |
|
690 /** The item representing the assignment's left hand side. |
|
691 */ |
|
692 Item lhs; |
|
693 |
|
694 AssignItem(Item lhs) { |
|
695 super(lhs.typecode); |
|
696 this.lhs = lhs; |
|
697 } |
|
698 |
|
699 Item load() { |
|
700 lhs.stash(typecode); |
|
701 lhs.store(); |
|
702 return stackItem[typecode]; |
|
703 } |
|
704 |
|
705 void duplicate() { |
|
706 load().duplicate(); |
|
707 } |
|
708 |
|
709 void drop() { |
|
710 lhs.store(); |
|
711 } |
|
712 |
|
713 void stash(int toscode) { |
|
714 Assert.error(); |
|
715 } |
|
716 |
|
717 int width() { |
|
718 return lhs.width() + Code.width(typecode); |
|
719 } |
|
720 |
|
721 public String toString() { |
|
722 return "assign(lhs = " + lhs + ")"; |
|
723 } |
|
724 } |
|
725 |
|
726 /** An item representing a conditional or unconditional jump. |
|
727 */ |
|
728 class CondItem extends Item { |
|
729 |
|
730 /** A chain encomassing all jumps that can be taken |
|
731 * if the condition evaluates to true. |
|
732 */ |
|
733 Chain trueJumps; |
|
734 |
|
735 /** A chain encomassing all jumps that can be taken |
|
736 * if the condition evaluates to false. |
|
737 */ |
|
738 Chain falseJumps; |
|
739 |
|
740 /** The jump's opcode. |
|
741 */ |
|
742 int opcode; |
|
743 |
|
744 /* |
|
745 * An abstract syntax tree of this item. It is needed |
|
746 * for branch entries in 'CharacterRangeTable' attribute. |
|
747 */ |
|
748 JCTree tree; |
|
749 |
|
750 CondItem(int opcode, Chain truejumps, Chain falsejumps) { |
|
751 super(BYTEcode); |
|
752 this.opcode = opcode; |
|
753 this.trueJumps = truejumps; |
|
754 this.falseJumps = falsejumps; |
|
755 } |
|
756 |
|
757 Item load() { |
|
758 Chain trueChain = null; |
|
759 Chain falseChain = jumpFalse(); |
|
760 if (!isFalse()) { |
|
761 code.resolve(trueJumps); |
|
762 code.emitop0(iconst_1); |
|
763 trueChain = code.branch(goto_); |
|
764 } |
|
765 if (falseChain != null) { |
|
766 code.resolve(falseChain); |
|
767 code.emitop0(iconst_0); |
|
768 } |
|
769 code.resolve(trueChain); |
|
770 return stackItem[typecode]; |
|
771 } |
|
772 |
|
773 void duplicate() { |
|
774 load().duplicate(); |
|
775 } |
|
776 |
|
777 void drop() { |
|
778 load().drop(); |
|
779 } |
|
780 |
|
781 void stash(int toscode) { |
|
782 Assert.error(); |
|
783 } |
|
784 |
|
785 CondItem mkCond() { |
|
786 return this; |
|
787 } |
|
788 |
|
789 Chain jumpTrue() { |
|
790 if (tree == null) return Code.mergeChains(trueJumps, code.branch(opcode)); |
|
791 // we should proceed further in -Xjcov mode only |
|
792 int startpc = code.curCP(); |
|
793 Chain c = Code.mergeChains(trueJumps, code.branch(opcode)); |
|
794 code.crt.put(tree, CRTable.CRT_BRANCH_TRUE, startpc, code.curCP()); |
|
795 return c; |
|
796 } |
|
797 |
|
798 Chain jumpFalse() { |
|
799 if (tree == null) return Code.mergeChains(falseJumps, code.branch(Code.negate(opcode))); |
|
800 // we should proceed further in -Xjcov mode only |
|
801 int startpc = code.curCP(); |
|
802 Chain c = Code.mergeChains(falseJumps, code.branch(Code.negate(opcode))); |
|
803 code.crt.put(tree, CRTable.CRT_BRANCH_FALSE, startpc, code.curCP()); |
|
804 return c; |
|
805 } |
|
806 |
|
807 CondItem negate() { |
|
808 CondItem c = new CondItem(Code.negate(opcode), falseJumps, trueJumps); |
|
809 c.tree = tree; |
|
810 return c; |
|
811 } |
|
812 |
|
813 int width() { |
|
814 // a CondItem doesn't have a size on the stack per se. |
|
815 throw new AssertionError(); |
|
816 } |
|
817 |
|
818 boolean isTrue() { |
|
819 return falseJumps == null && opcode == goto_; |
|
820 } |
|
821 |
|
822 boolean isFalse() { |
|
823 return trueJumps == null && opcode == dontgoto; |
|
824 } |
|
825 |
|
826 public String toString() { |
|
827 return "cond(" + Code.mnem(opcode) + ")"; |
|
828 } |
|
829 } |
|
830 } |