1 /*
2 * Copyright (c) 1996, 2020, 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.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23 package org.openjdk.asmtools.jasm;
24
25 import org.openjdk.asmtools.jasm.Tables.ConstType;
26
27 import java.io.IOException;
28 import java.util.ArrayList;
29 import java.util.Hashtable;
30 import java.util.Iterator;
31 import java.util.stream.Collectors;
32
33 /**
34 * ConstantPool
35 *
36 * ConstantPool is the class responsible for maintaining constants for a given class file.
37 *
38 */
39 public class ConstantPool implements Iterable<ConstantPool.ConstCell> {
40
41
42 static public enum ReferenceRank {
43 LDC(0), // 0 - highest - ref from ldc
44 ANY(1), // 1 - any ref
45 NO(2); // 2 - no ref
46 final int rank;
47 ReferenceRank(int rank) {
48 this.rank = rank;
49 }
50 }
51
52 /*-------------------------------------------------------- */
53 /* ConstantPool Inner Classes */
54 /**
55 * ConstValue
56 *
57 * A (typed) tagged value in the constant pool.
58 */
59 static public class ConstValue {
60
61 protected ConstType tag;
62 protected boolean isSet = false;
63 private boolean visited = false;
64
65 public ConstValue(ConstType tag) {
66 this.tag = tag;
67 }
68
69 public int size() {
70 return 1;
71 }
72
73 public boolean hasValue() {
74 return isSet;
75 }
76
77 /**
78 * Compute the hash-code, based on the value of the native (_hashCode()) hashcode.
79 */
80 @Override
81 public int hashCode() {
82 if (visited) {
83 throw new Parser.CompilerError("CV hash:" + this);
84 }
85 visited = true;
86 int res = _hashCode() + tag.value() * 1023;
87 visited = false;
88 return res;
89 }
90
91 // sub-classes override this.
92 // this is the default for getting a hash code.
93 protected int _hashCode() {
94 return 37;
95 }
96
97 /**
98 * Compares this object to the specified object.
99 *
100 * Sub-classes must override this
101 *
102 * @param obj the object to compare with
103 * @return true if the objects are the same; false otherwise.
104 */
105 @Override
106 public boolean equals(Object obj) {
107 return false;
108 }
109
110 @Override
111 public String toString() {
112 String tagstr = tag.printval();
113 String retval = "";
114 if (tagstr == null) {
115 return "BOGUS_TAG:" + tag;
116 }
117
118 String valueStr = _toString();
119 if (valueStr != null) {
120 retval = "<" + tagstr + " " + valueStr + ">";
121 } else {
122 retval = "<" + tagstr + ">";
123 }
124 return retval;
125 }
126
127 protected String _toString() {
128 return "";
129 }
130
131 public void write(CheckedDataOutputStream out) throws IOException {
132 out.writeByte(tag.value());
133 }
134 } // end ConstValue
135
136 /**
137 * ConstValue
138 *
139 * A (typed) tagged value in the constant pool.
140 */
141 static public class ConstValue_Zero extends ConstValue {
142
143 public ConstValue_Zero() {
144 super(ConstType.CONSTANT_ZERO);
145 isSet = false;
146 }
147
148 @Override
149 public void write(CheckedDataOutputStream out) throws IOException {
150 throw new Parser.CompilerError("Trying to write Constant 0.");
151 }
152 }
153
154 /**
155 * ConstValue
156 *
157 * A (typed) tagged value in the constant pool.
158 */
159 static public class ConstValue_String extends ConstValue {
160
161 String value;
162
163 public ConstValue_String(String value) {
164 super(ConstType.CONSTANT_UTF8);
165 this.value = value;
166 isSet = (value != null);
167 }
168
169 @Override
170 protected String _toString() {
171 return value;
172 }
173
174 @Override
175 protected int _hashCode() {
176 return value.hashCode();
177 }
178
179 @Override
180 public boolean equals(Object obj) {
181 if ((obj == null) || !(obj instanceof ConstValue_String)) {
182 return false;
183 }
184 ConstValue_String dobj = (ConstValue_String) obj;
185 if (tag != dobj.tag) {
186 return false;
187 }
188 return value.equals(dobj.value);
189 }
190
191 @Override
192 public void write(CheckedDataOutputStream out) throws IOException {
193 super.write(out);
194 out.writeUTF(value);
195 }
196 }
197
198 /**
199 * ConstValue
200 *
201 * A (typed) tagged value in the constant pool.
202 */
203 static public class ConstValue_Integer extends ConstValue {
204
205 Integer value;
206
207 public ConstValue_Integer(ConstType tag, Integer value) {
208 super(tag);
209 this.value = value;
210 isSet = (value != null);
211 }
212
213 @Override
214 protected String _toString() {
215 return value.toString();
216 }
217
218 @Override
219 public boolean equals(Object obj) {
220 if ((obj == null) || !(obj instanceof ConstValue_Integer)) {
221 return false;
222 }
223 ConstValue_Integer dobj = (ConstValue_Integer) obj;
224 if (tag != dobj.tag) {
225 return false;
226 }
227 return value.equals(dobj.value);
228 }
229
230 @Override
231 protected int _hashCode() {
232 return value.hashCode();
233 }
234
235 @Override
236 public void write(CheckedDataOutputStream out) throws IOException {
237 super.write(out);
238 out.writeInt(value.intValue());
239 }
240 }
241
242 /**
243 * ConstValue
244 *
245 * A (typed) tagged value in the constant pool.
246 */
247 static public class ConstValue_Long extends ConstValue {
248
249 Long value;
250
251 public ConstValue_Long(ConstType tag, Long value) {
252 super(tag);
253 this.value = value;
254 isSet = (value != null);
255 }
256
257 @Override
258 public int size() {
259 return 2;
260 }
261
262 @Override
263 protected String _toString() {
264 return value.toString();
265 }
266
267 @Override
268 public boolean equals(Object obj) {
269 if ((obj == null) || !(obj instanceof ConstValue_Long)) {
270 return false;
271 }
272 ConstValue_Long dobj = (ConstValue_Long) obj;
273 if (tag != dobj.tag) {
274 return false;
275 }
276 return value.equals(dobj.value);
277 }
278
279 @Override
280 protected int _hashCode() {
281 return value.hashCode();
282 }
283
284 @Override
285 public void write(CheckedDataOutputStream out) throws IOException {
286 super.write(out);
287 out.writeLong(value.longValue());
288 }
289 }
290
291 /**
292 * ConstValue
293 *
294 * A (typed) tagged value in the constant pool.
295 */
296 static public class ConstValue_Cell extends ConstValue {
297
298 ConstCell cell;
299
300 public ConstValue_Cell(ConstType tag, ConstCell cell) {
301 super(tag);
302 this.cell = cell;
303 isSet = (cell != null);
304 }
305
306 @Override
307 protected String _toString() {
308 return cell.toString();
309 }
310
311 @Override
312 public boolean equals(Object obj) {
313 if ((obj == null) || !(obj instanceof ConstValue_Cell)) {
314 return false;
315 }
316 ConstValue_Cell dobj = (ConstValue_Cell) obj;
317 if (tag != dobj.tag) {
318 return false;
319 }
320 return cell.equals(dobj.cell);
321 }
322
323 @Override
324 protected int _hashCode() {
325 return cell.hashCode();
326 }
327
328 @Override
329 public void write(CheckedDataOutputStream out) throws IOException {
330 super.write(out);
331 cell.write(out);
332 }
333 }
334
335 /**
336 * ConstValue
337 *
338 * A (typed) tagged value in the constant pool.
339 */
340 static public class ConstValue_Pair extends ConstValue {
341
342 ConstCell left, right;
343
344 public ConstValue_Pair(ConstType tag, ConstCell left, ConstCell right) {
345 super(tag);
346 this.left = left;
347 this.right = right;
348 isSet = (left != null && right != null);
349 }
350
351 @Override
352 public boolean equals(Object obj) {
353 if ((obj == null) || !(obj instanceof ConstValue_Pair)) {
354 return false;
355 }
356 ConstValue_Pair dobj = (ConstValue_Pair) obj;
357 if (tag != dobj.tag) {
358 return false;
359 }
360 if (dobj.left != null)
361 if (!dobj.left.equals(left))
362 return false;
363 if (dobj.right != null)
364 if (!dobj.right.equals(right))
365 return false;
366 return true;
367 }
368
369 @Override
370 public String toString() {
371 return super.toString() + "{" + left + "," + right + "}";
372 }
373
374 @Override
375 protected int _hashCode() {
376 return left.hashCode() * right.hashCode();
377 }
378
379 @Override
380 public void write(CheckedDataOutputStream out) throws IOException {
381 super.write(out);
382 if (tag == ConstType.CONSTANT_METHODHANDLE) {
383 out.writeByte(left.arg); // write subtag value
384 } else {
385 out.writeShort(left.arg);
386 }
387 out.writeShort(right.arg);
388 }
389 }
390
391 static public class ConstValue_IndyOrCondyPair extends ConstValue {
392 BootstrapMethodData bsmData;
393 ConstantPool.ConstCell napeCell;
394
395 protected ConstValue_IndyOrCondyPair(ConstType tag, BootstrapMethodData bsmdata, ConstCell napeCell) {
396 super(tag);
397 assert (tag == ConstType.CONSTANT_DYNAMIC && ConstValue_CondyPair.class.isAssignableFrom(getClass())) ||
398 tag == ConstType.CONSTANT_INVOKEDYNAMIC && ConstValue_IndyPair.class.isAssignableFrom(getClass());
399
400 this.bsmData = bsmdata;
401 this.napeCell = napeCell;
402 isSet = (bsmdata != null && napeCell != null);
403 }
404
405 @Override
406 public boolean equals(Object obj) {
407 if ((obj == null) || !(getClass().isInstance(obj))) {
408 return false;
409 }
410
411 ConstValue_IndyOrCondyPair iobj = (ConstValue_IndyOrCondyPair) obj;
412 return (iobj.bsmData == bsmData) && (iobj.napeCell == napeCell);
413 }
414
415 @Override
416 public String toString() {
417 return super.toString() + "{" + bsmData + "," + napeCell + "}";
418 }
419
420 @Override
421 protected int _hashCode() {
422 if (bsmData.isPlaceholder()) {
423 return napeCell.hashCode();
424 }
425 return bsmData.hashCode() * napeCell.hashCode();
426 }
427
428 @Override
429 public void write(CheckedDataOutputStream out) throws IOException {
430 super.write(out);
431 out.writeShort(bsmData.arg);
432 out.writeShort(napeCell.arg);
433 }
434 }
435 /**
436 * ConstValue
437 *
438 * A (typed) tagged value in the constant pool.
439 */
440 static public class ConstValue_CondyPair extends ConstValue_IndyOrCondyPair {
441
442 public ConstValue_CondyPair(BootstrapMethodData bsmdata, ConstCell napeCell) {
443 super(ConstType.CONSTANT_DYNAMIC, bsmdata, napeCell);
444 }
445 }
446
447 /**
448 * ConstValue
449 *
450 * A (typed) tagged value in the constant pool.
451 */
452 static public class ConstValue_IndyPair extends ConstValue_IndyOrCondyPair {
453
454 public ConstValue_IndyPair(BootstrapMethodData bsmdata, ConstCell napeCell) {
455 super(ConstType.CONSTANT_INVOKEDYNAMIC, bsmdata, napeCell);
456 }
457 }
458
459 /*-------------------------------------------------------- */
460 /* ConstantPool Inner Classes */
461 /**
462 * ConstantCell
463 *
464 * ConstantCell is a type of data that can be in a constant pool.
465 */
466 static public class ConstCell extends Argument implements Data {
467
468 ConstValue ref;
469 // 0 - highest - ref from ldc, 1 - any ref, 2 - no ref
470 ReferenceRank rank = ReferenceRank.NO;
471
472 ConstCell(int arg, ConstValue ref) {
473 this.arg = arg;
474 this.ref = ref;
475 }
476
477 ConstCell(ConstValue ref) {
478 this(NotSet, ref);
479 }
480
481 ConstCell(int arg) {
482 this(arg, null);
483 }
484
485 @Override
486 public int getLength() {
487 return 2;
488 }
489
490 @Override
491 public void write(CheckedDataOutputStream out) throws IOException {
492 out.writeShort(arg);
493 }
494
495 public void setRank(ReferenceRank rank) {
496 // don't change a short ref to long due to limitation of ldc - max 256 indexes allowed
497 if( this.rank != ReferenceRank.LDC) {
498 this.rank = rank;
499 }
500 }
501
502 @Override
503 public int hashCode() {
504 if (arg == NotSet) {
505 if (ref != null) {
506 return ref.hashCode();
507 } else {
508 throw new Parser.CompilerError("Can't generate Hash Code, Null ConstCell Reference.");
509 }
510 }
511 return arg;
512 }
513
514 @Override
515 public boolean equals(Object obj) {
516 if (obj == null) {
517 return false;
518 }
519 ConstCell cc = (ConstCell)obj;
520 if( cc.ref == null ) {
521 return this.ref == null && cc.rank == this.rank;
522 }
523 return cc.ref.equals(this.ref) && cc.rank == this.rank;
524 }
525
526 public boolean isUnset() {
527 return (arg == NotSet) && (ref == null);
528 }
529
530 @Override
531 public String toString() {
532 return "#" + arg + "=" + ref;
533 }
534 }
535
536 /**
537 * CPVisitor
538 *
539 * CPVisitor base class defining a visitor for decoding constants.
540 */
541 public static class CPTagVisitor<R> implements Constants {
542
543 public CPTagVisitor() {
544 }
545
546 public final R visit(ConstType tag) {
547 R retVal = null;
548 switch (tag) {
549 case CONSTANT_UTF8:
550 retVal = visitUTF8(tag);
551 break;
552 case CONSTANT_INTEGER:
553 retVal = visitInteger(tag);
554 break;
555 case CONSTANT_FLOAT:
556 retVal = visitFloat(tag);
557 break;
558 case CONSTANT_DOUBLE:
559 retVal = visitDouble(tag);
560 break;
561 case CONSTANT_LONG:
562 retVal = visitLong(tag);
563 break;
564 case CONSTANT_METHODTYPE:
565 retVal = visitMethodtype(tag);
566 break;
567 case CONSTANT_STRING:
568 retVal = visitString(tag);
569 break;
570 case CONSTANT_CLASS:
571 retVal = visitClass(tag);
572 break;
573 case CONSTANT_METHOD:
574 retVal = visitMethod(tag);
575 break;
576 case CONSTANT_FIELD:
577 retVal = visitField(tag);
578 break;
579 case CONSTANT_INTERFACEMETHOD:
580 retVal = visitInterfacemethod(tag);
581 break;
582 case CONSTANT_NAMEANDTYPE:
583 retVal = visitNameandtype(tag);
584 break;
585 case CONSTANT_METHODHANDLE:
586 retVal = visitMethodhandle(tag);
587 break;
588 case CONSTANT_DYNAMIC:
589 retVal = visitDynamic(tag);
590 break;
591 case CONSTANT_INVOKEDYNAMIC:
592 retVal = visitInvokedynamic(tag);
593 break;
594 default:
595 visitDefault(tag);
596 }
597 return retVal;
598 }
599
600 public R visitUTF8(ConstType tag) {
601 return null;
602 }
603
604 public R visitInteger(ConstType tag) {
605 return null;
606 }
607
608 public R visitFloat(ConstType tag) {
609 return null;
610 }
611
612 public R visitDouble(ConstType tag) {
613 return null;
614 }
615
616 public R visitLong(ConstType tag) {
617 return null;
618 }
619
620 public R visitMethodtype(ConstType tag) {
621 return null;
622 }
623
624 public R visitString(ConstType tag) {
625 return null;
626 }
627
628 public R visitClass(ConstType tag) {
629 return null;
630 }
631
632 public R visitMethod(ConstType tag) {
633 return null;
634 }
635
636 public R visitField(ConstType tag) {
637 return null;
638 }
639
640 public R visitInterfacemethod(ConstType tag) {
641 return null;
642 }
643
644 public R visitNameandtype(ConstType tag) {
645 return null;
646 }
647
648 public R visitMethodhandle(ConstType tag) {
649 return null;
650 }
651
652 public R visitDynamic(ConstType tag) {
653 return null;
654 }
655
656 public R visitInvokedynamic(ConstType tag) {
657 return null;
658 }
659
660 public R visitModule(ConstType tag) {
661 return null;
662 }
663
664 public R visitPackage(ConstType tag) {
665 return null;
666 }
667
668 public void visitDefault(ConstType tag) {
669 }
670 }
671
672 /**
673 * CPVisitor
674 *
675 * CPVisitor base class defining a visitor for decoding constants.
676 */
677 public static class CPVisitor<R> implements Constants {
678
679 public CPVisitor() {
680 }
681
682 public final R visit(ConstValue val) {
683 R retVal = null;
684 ConstType tag = val.tag;
685 switch (tag) {
686 case CONSTANT_UTF8:
687 retVal = visitUTF8((ConstValue_String) val);
688 break;
689 case CONSTANT_INTEGER:
690 retVal = visitInteger((ConstValue_Integer) val);
691 break;
692 case CONSTANT_FLOAT:
693 retVal = visitFloat((ConstValue_Integer) val);
694 break;
695 case CONSTANT_DOUBLE:
696 retVal = visitDouble((ConstValue_Long) val);
697 break;
698 case CONSTANT_LONG:
699 retVal = visitLong((ConstValue_Long) val);
700 break;
701 case CONSTANT_METHODTYPE:
702 retVal = visitMethodtype((ConstValue_Cell) val);
703 break;
704 case CONSTANT_STRING:
705 retVal = visitString((ConstValue_Cell) val);
706 break;
707 case CONSTANT_CLASS:
708 retVal = visitClass((ConstValue_Cell) val);
709 break;
710 case CONSTANT_METHOD:
711 retVal = visitMethod((ConstValue_Pair) val);
712 break;
713 case CONSTANT_FIELD:
714 retVal = visitField((ConstValue_Pair) val);
715 break;
716 case CONSTANT_INTERFACEMETHOD:
717 retVal = visitInterfacemethod((ConstValue_Pair) val);
718 break;
719 case CONSTANT_NAMEANDTYPE:
720 retVal = visitNameandtype((ConstValue_Pair) val);
721 break;
722 case CONSTANT_METHODHANDLE:
723 retVal = visitMethodhandle((ConstValue_Pair) val);
724 break;
725 case CONSTANT_DYNAMIC:
726 retVal = visitDynamic((ConstValue_CondyPair) val);
727 break;
728 case CONSTANT_INVOKEDYNAMIC:
729 retVal = visitInvokedynamic((ConstValue_IndyPair) val);
730 break;
731 case CONSTANT_MODULE:
732 retVal = visitModule((ConstValue_Cell) val);
733 break;
734 case CONSTANT_PACKAGE:
735 retVal = visitPackage((ConstValue_Cell) val);
736 break;
737 default:
738 visitDefault(tag);
739 }
740 return retVal;
741 }
742
743 public R visitUTF8(ConstValue_String p) {
744 return null;
745 }
746
747 ;
748 public R visitInteger(ConstValue_Integer p) {
749 return null;
750 }
751
752 ;
753 public R visitFloat(ConstValue_Integer p) {
754 return null;
755 }
756
757 ;
758 public R visitDouble(ConstValue_Long p) {
759 return null;
760 }
761
762 ;
763 public R visitLong(ConstValue_Long p) {
764 return null;
765 }
766
767 ;
768 public R visitMethodtype(ConstValue_Cell p) {
769 return null;
770 }
771
772 ;
773 public R visitString(ConstValue_Cell p) {
774 return null;
775 }
776
777 ;
778 public R visitClass(ConstValue_Cell p) {
779 return null;
780 }
781
782 ;
783 public R visitMethod(ConstValue_Pair p) {
784 return null;
785 }
786
787 ;
788 public R visitField(ConstValue_Pair p) {
789 return null;
790 }
791
792 ;
793 public R visitInterfacemethod(ConstValue_Pair p) {
794 return null;
795 }
796
797 ;
798 public R visitNameandtype(ConstValue_Pair p) {
799 return null;
800 }
801
802 ;
803 public R visitMethodhandle(ConstValue_Pair p) {
804 return null;
805 }
806
807 ;
808 public R visitDynamic(ConstValue_CondyPair p) { return null;}
809
810 ;
811 public R visitInvokedynamic(ConstValue_IndyPair p) { return null;}
812
813 ;
814 public R visitModule(ConstValue_Cell p) { return null; }
815
816 ;
817 public R visitPackage(ConstValue_Cell p) { return null; }
818 ;
819
820 public void visitDefault(ConstType tag) {}
821 ;
822
823 }
824
825
826
827 /*-------------------------------------------------------- */
828 /* Constant Pool Fields */
829
830 private ArrayList<ConstCell> pool = new ArrayList<>(20);
831
832 private final ConstValue ConstValue0
833 = new ConstValue_String("");
834 // private final ConstValue ConstValue0 =
835 // new ConstValue(CONSTANT_UTF8, "");
836 private final ConstCell nullConst
837 = new ConstCell(null);
838 private final ConstCell constant_0
839 = new ConstCell(new ConstValue_Zero());
840 // private final ConstCell constant_0 =
841 // new ConstCell(new ConstValue(CONSTANT_ZERO, null));
842
843 // For hashing by value
844 Hashtable<ConstValue, ConstCell> cpoolHashByValue
845 = new Hashtable<>(40);
846
847 public Environment env;
848
849 private static boolean debugCP = false;
850
851 /*-------------------------------------------------------- */
852 /**
853 * main constructor
854 *
855 * @param env The error reporting environment
856 */
857 public ConstantPool(Environment env) {
858 this.env = env;
859 pool.add(constant_0);
860
861 }
862
863 public void debugStr(String s) {
864 if (debugCP) {
865 env.traceln(s);
866 }
867 }
868
869 @Override
870 public Iterator<ConstCell> iterator() {
871 return pool.iterator();
872 }
873
874
875 /*
876 * Fix Refs in constant pool.
877 *
878 * This is used when scanning JASM files produced from JDis with the verbose
879 * option (eg. where the constant pool is declared in the jasm itself). In
880 * this scenario, we need two passes - the first pass to scan the entries
881 * (which creates constant references with indexes, but no reference values);
882 * and the second pass, which links references to existing constants.
883 *
884 */
885 public void fixRefsInPool() {
886 // used to fix CP refs when a constant pool is constructed by refs alone.
887 env.traceln("Fixing CP for explicit Constant Entries.");
888 int i = 0;
889 // simply iterate through the pool.
890 for (ConstCell item : pool) {
891 i += 1;
892 // first item is always null
893 if (item == null) {
894 continue;
895 }
896
897 checkAndFixCPRef(i, item);
898 }
899 }
900
901 protected void CheckGlobals() {
902 env.traceln("Checking Globals");
903 //
904 // This fn will put empty UTF8 string entries on any unset
905 // CP entries - before the last CP entry.
906 //
907 for (int cpx = 1; cpx < pool.size(); cpx++) {
908 ConstCell cell = pool.get(cpx);
909 if (cell == nullConst) { // gap
910 cell = new ConstCell(cpx, ConstValue0);
911 pool.set(cpx, cell);
912 }
913 ConstValue cval = cell.ref;
914 if ((cval == null) || !cval.hasValue()) {
915 String name = Integer.toString(cpx);
916 env.error("const.undecl", name);
917 }
918 }
919 }
920
921 /*
922 * Helper function for "fixRefsInPool"
923 *
924 * Does recursive checking of references,
925 * using a locally-defined visitor.
926 */
927 private void checkAndFixCPRef(int i, ConstCell item) {
928 ConstValue cv = item.ref;
929 if (cv != null) {
930 fixCPVstr.visit(cv);
931 }
932 }
933
934 private CPVisitor<Void> fixCPVstr = new CPVisitor<Void>() {
935 @Override
936 public Void visitUTF8(ConstValue_String p) {
937 return null;
938 }
939
940 ;
941 @Override
942 public Void visitInteger(ConstValue_Integer p) {
943 return null;
944 }
945
946 ;
947 @Override
948 public Void visitFloat(ConstValue_Integer p) {
949 return null;
950 }
951
952 ;
953 @Override
954 public Void visitDouble(ConstValue_Long p) {
955 return null;
956 }
957
958 ;
959 @Override
960 public Void visitLong(ConstValue_Long p) {
961 return null;
962 }
963
964 ;
965 @Override
966 public Void visitMethodtype(ConstValue_Cell p) {
967 handleClassRef(p);
968 return null;
969 }
970
971 ;
972 @Override
973 public Void visitString(ConstValue_Cell p) {
974 handleClassRef(p);
975 return null;
976 }
977
978 ;
979 @Override
980 public Void visitClass(ConstValue_Cell p) {
981 handleClassRef(p);
982 return null;
983 }
984
985 ;
986 @Override
987 public Void visitMethod(ConstValue_Pair p) {
988 handleMemberRef(p);
989 return null;
990 }
991
992 ;
993 @Override
994 public Void visitField(ConstValue_Pair p) {
995 handleMemberRef(p);
996 return null;
997 }
998
999 ;
1000 @Override
1001 public Void visitInterfacemethod(ConstValue_Pair p) {
1002 handleMemberRef(p);
1003 return null;
1004 }
1005
1006 ;
1007 @Override
1008 public Void visitNameandtype(ConstValue_Pair p) {
1009 handleMemberRef(p);
1010 return null;
1011 }
1012
1013 ;
1014 @Override
1015 public Void visitMethodhandle(ConstValue_Pair p) {
1016 handleMemberRef(p);
1017 return null;
1018 }
1019
1020 ;
1021 @Override
1022 public Void visitDynamic(ConstValue_CondyPair p) {
1023 return null;
1024 }
1025
1026 ;
1027 @Override
1028 public Void visitInvokedynamic(ConstValue_IndyPair p) {
1029 return null;
1030 }
1031 ;
1032
1033 @Override
1034 public Void visitModule(ConstValue_Cell p) {
1035 handleClassRef(p);
1036 return null;
1037 }
1038 ;
1039
1040 @Override
1041 public Void visitPackage(ConstValue_Cell p) {
1042 handleClassRef(p);
1043 return null;
1044 }
1045 ;
1046
1047
1048 public void handleClassRef(ConstValue_Cell cv) {
1049 ConstCell clref = cv.cell;
1050 if (clref.ref == null) {
1051 ConstCell refval = cpool_get(clref.arg);
1052 if (refval != null) {
1053 checkAndFixCPRef(clref.arg, refval);
1054 clref.ref = refval.ref;
1055 } else {
1056 clref.ref = null;
1057 }
1058 // env.traceln("FIXED ConstPool[" + i + "](" + cv.TagString(cv.tag) + ") = " + cv.value);
1059 }
1060 }
1061
1062 public void handleMemberRef(ConstValue_Pair cv) {
1063 // env.traceln("ConstPool[" + i + "](" + cv.TagString(cv.tag) + ") = " + cv.value);
1064 ConstCell clref = cv.left;
1065 ConstCell typref = cv.right;
1066 if (clref.ref == null) {
1067 ConstCell refval = cpool_get(clref.arg);
1068 if (refval != null) {
1069 checkAndFixCPRef(clref.arg, refval);
1070 clref.ref = refval.ref;
1071 } else {
1072 clref.ref = null;
1073 }
1074 // env.traceln("FIXED ConstPool[" + i + "](" + cv.TagString(cv.tag) + ") = " + cv.value);
1075 }
1076 if (typref.ref == null) {
1077 ConstCell refval = cpool_get(typref.arg);
1078 if (refval != null) {
1079 checkAndFixCPRef(typref.arg, refval);
1080 typref.ref = refval.ref;
1081 } else {
1082 typref.ref = null;
1083 }
1084 // env.traceln("FIXED ConstPool[" + i + "](" + cv.TagString(cv.tag) + ") = " + cv.value);
1085 }
1086 }
1087
1088 };
1089
1090 /*
1091 * Help debug Constant Pools
1092 */
1093 public void printPool() {
1094 int i = 0;
1095 for (ConstCell item : pool) {
1096 env.traceln("^^^^^^^^^^^^^ const #" + i + ": " + item);
1097 i += 1;
1098 }
1099 }
1100
1101 private ConstCell cpool_get(int cpx) {
1102 if (cpx >= pool.size()) {
1103 return null;
1104 }
1105 return pool.get(cpx);
1106 }
1107
1108 private void cpool_set(int cpx, ConstCell cell, int sz) {
1109 debugStr("cpool_set1: " + cpx + " " + cell);
1110 debugStr("param_size: " + sz);
1111 debugStr("pool_size: " + pool.size());
1112 cell.arg = cpx;
1113 if (cpx + sz >= pool.size()) {
1114 debugStr("calling ensureCapacity( " + (cpx + sz + 1) + ")");
1115 int low = pool.size();
1116 int high = cpx + sz;
1117 for (int i = 0; i < high - low; i++) {
1118 pool.add(nullConst);
1119 }
1120 }
1121 pool.set(cpx, cell);
1122 if (sz == 2) {
1123 pool.set(cpx + 1, new ConstCell(cpx + 1, ConstValue0));
1124 }
1125 debugStr(" cpool_set2: " + cpx + " " + cell);
1126 }
1127
1128 protected ConstCell uncheckedGetCell(int cpx) { // by index
1129 return pool.get(cpx);
1130 }
1131
1132 public ConstCell getCell(int cpx) { // by index
1133 ConstCell cell = cpool_get(cpx);
1134 if (cell != null) {
1135 return cell;
1136 }
1137 cell = new ConstCell(cpx, null);
1138 return cell;
1139 }
1140
1141 public void setCell(int cpx, ConstCell cell) {
1142 ConstValue value = cell.ref;
1143 if (value == null) {
1144 throw new Parser.CompilerError(env.errorStr("comperr.constcell.nullvalset"));
1145 }
1146 int sz = value.size();
1147
1148 if (cpx == 0) {
1149 // It is correct to warn about redeclaring constant zero,
1150 // since this value is never written out to a class file.
1151 env.error("warn.const0.redecl");
1152 } else {
1153 if ((cpool_get(cpx) != null) || ((sz == 2) && (cpool_get(cpx + 1) != null))) {
1154 String name = "#" + cpx;
1155 env.error("const.redecl", name);
1156 return;
1157 }
1158 if (cell.isSet() && (cell.arg != cpx)) {
1159 env.traceln("setCell: new ConstCell");
1160 cell = new ConstCell(value);
1161 }
1162 }
1163 cpool_set(cpx, cell, sz);
1164 }
1165
1166 protected void NumberizePool() {
1167 env.traceln("NumberizePool");
1168
1169 for (ReferenceRank rank : ReferenceRank.values()) {
1170 for (ConstCell cell : cpoolHashByValue.values().stream().
1171 filter(v-> !v.isSet() && rank.equals(v.rank)).
1172 collect(Collectors.toList())) {
1173
1174 ConstValue value = cell.ref;
1175 if (value == null) {
1176 throw new Parser.CompilerError(env.errorStr("comperr.constcell.nullvalhash"));
1177 }
1178 int sz = value.size(), cpx;
1179 find:
1180 for (cpx = 1; cpx < pool.size(); cpx++) {
1181 if ((pool.get(cpx) == nullConst) && ((sz == 1) || (pool.get(cpx + 1) == nullConst))) {
1182 break find;
1183 }
1184 }
1185 cpool_set(cpx, cell, sz);
1186 }
1187 }
1188
1189 ConstCell firstCell = cpool_get(0);
1190 firstCell.arg = 0;
1191 }
1192
1193 public ConstCell FindCell(ConstValue ref) {
1194 if (ref == null) {
1195 throw new Parser.CompilerError(env.errorStr("comperr.constcell.nullval"));
1196 }
1197 ConstCell pconst = null;
1198 try {
1199 pconst = cpoolHashByValue.get(ref);
1200 } catch (Parser.CompilerError e) {
1201 throw new Parser.CompilerError(env.errorStr("comperr.constcell.nullvalhash"));
1202 }
1203 // If we fund a cached ConstValue
1204 if (pconst != null) {
1205 ConstValue value = pconst.ref;
1206 if (!value.equals(ref)) {
1207 throw new Parser.CompilerError(env.errorStr("comperr.val.noteq"));
1208 }
1209 return pconst;
1210 }
1211 // If we didn't find a cached ConstValue
1212 // Add it to the cache
1213 pconst = new ConstCell(ref);
1214 cpoolHashByValue.put(ref, pconst);
1215 return pconst;
1216 }
1217
1218 public ConstCell FindCell(ConstType tag, String value) {
1219 return FindCell(new ConstValue_String(value));
1220 }
1221
1222 public ConstCell FindCell(ConstType tag, Integer value) {
1223 return FindCell(new ConstValue_Integer(tag, value));
1224 }
1225
1226 public ConstCell FindCell(ConstType tag, Long value) {
1227 return FindCell(new ConstValue_Long(tag, value));
1228 }
1229
1230 public ConstCell FindCell(ConstType tag, ConstCell value) {
1231 return FindCell(new ConstValue_Cell(tag, value));
1232 }
1233
1234 public ConstCell FindCell(ConstType tag, ConstCell left, ConstCell right) {
1235 return FindCell(new ConstValue_Pair(tag, left, right));
1236 }
1237
1238 public ConstCell FindCellAsciz(String str) {
1239 return FindCell(ConstType.CONSTANT_UTF8, str);
1240 }
1241
1242 public ConstCell FindCellClassByName(String name) { return FindCell(ConstType.CONSTANT_CLASS, FindCellAsciz(name)); }
1243
1244 public ConstCell FindCellModuleByName(String name) { return FindCell(ConstType.CONSTANT_MODULE, FindCellAsciz(name)); }
1245
1246 public ConstCell FindCellPackageByName(String name) { return FindCell(ConstType.CONSTANT_PACKAGE, FindCellAsciz(name)); }
1247
1248 public void write(CheckedDataOutputStream out) throws IOException {
1249 // Write the constant pool
1250 int length = pool.size();
1251 out.writeShort(length);
1252 int i;
1253 env.traceln("wr.pool:size=" + length);
1254 for (i = 1; i < length;) {
1255 ConstCell cell = pool.get(i);
1256 ConstValue value = cell.ref;
1257 if (cell.arg != i) {
1258 throw new Parser.CompilerError(env.errorStr("comperr.constcell.invarg", Integer.toString(i), cell.arg));
1259 }
1260 value.write(out);
1261 i += value.size();
1262 }
1263 }
1264 }