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 }