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 }