001    /*
002     *  This file is part of the Jikes RVM project (http://jikesrvm.org).
003     *
004     *  This file is licensed to You under the Eclipse Public License (EPL);
005     *  You may not use this file except in compliance with the License. You
006     *  may obtain a copy of the License at
007     *
008     *      http://www.opensource.org/licenses/eclipse-1.0.php
009     *
010     *  See the COPYRIGHT.txt file distributed with this work for information
011     *  regarding copyright ownership.
012     */
013    package org.jikesrvm.classloader;
014    
015    import org.jikesrvm.VM;
016    import org.jikesrvm.SizeConstants;
017    import org.jikesrvm.objectmodel.TIBLayoutConstants;
018    import org.jikesrvm.util.ImmutableEntryHashSetRVM;
019    import org.vmmagic.unboxed.Offset;
020    
021    /**
022     *  An interface method signature is a pair of atoms:
023     *  interfaceMethodName + interfaceMethodDescriptor.
024     */
025    public final class InterfaceMethodSignature implements TIBLayoutConstants, SizeConstants {
026    
027      /**
028       * Used to canonicalize InterfaceMethodSignatures
029       */
030      private static final ImmutableEntryHashSetRVM<InterfaceMethodSignature> dictionary =
031        new ImmutableEntryHashSetRVM<InterfaceMethodSignature>();
032    
033      /**
034       * Used to assign ids. Don't use id 0 to allow clients to use id 0 as a 'null'.
035       */
036      private static int nextId = 1;
037    
038      /**
039       * Name of the interface method
040       */
041      private final Atom name;
042    
043      /**
044       * Descriptor of the interface method
045       */
046      private final Atom descriptor;
047    
048      /**
049       * Id of this interface method signature (not used in hashCode or equals).
050       */
051      private final int id;
052    
053      private InterfaceMethodSignature(Atom name, Atom descriptor, int id) {
054        this.name = name;
055        this.descriptor = descriptor;
056        this.id = id;
057      }
058    
059      /**
060       * Find or create an interface method signature for the given method reference.
061       *
062       * @param ref     A reference to a supposed interface method
063       * @return the interface method signature
064       */
065      public static synchronized InterfaceMethodSignature findOrCreate(MemberReference ref) {
066        InterfaceMethodSignature key = new InterfaceMethodSignature(ref.getName(), ref.getDescriptor(), nextId+1);
067        InterfaceMethodSignature val = dictionary.get(key);
068        if (val != null) return val;
069        nextId++;
070        dictionary.add(key);
071        return key;
072      }
073    
074      /**
075       * @return name of the interface method
076       */
077      public Atom getName() {
078        return name;
079      }
080    
081      /**
082       * @return descriptor of hte interface method
083       */
084      public Atom getDescriptor() {
085        return descriptor;
086      }
087    
088      /**
089       * @return the id of thie interface method signature.
090       */
091      public int getId() { return id; }
092    
093      @Override
094      public String toString() {
095        return "{" + name + " " + descriptor + "}";
096      }
097    
098      @Override
099      public int hashCode() {
100        return name.hashCode() + descriptor.hashCode();
101      }
102    
103      @Override
104      public boolean equals(Object other) {
105        if (other instanceof InterfaceMethodSignature) {
106          InterfaceMethodSignature that = (InterfaceMethodSignature) other;
107          return name == that.name && descriptor == that.descriptor;
108        } else {
109          return false;
110        }
111      }
112    
113      /**
114       * If using embedded IMTs, Get offset of interface method slot in TIB.
115       * If using indirect IMTs, Get offset of interface method slot in IMT.
116       * Note that all methods with same name & descriptor map to the same slot.
117       * <p>
118       * TODO!! replace this stupid offset assignment algorithm with something more reasonable.
119       *
120       * @return offset in TIB/IMT
121       */
122      public Offset getIMTOffset() {
123        if (VM.VerifyAssertions) VM._assert(VM.BuildForIMTInterfaceInvocation);
124        int slot = id % IMT_METHOD_SLOTS;
125        return Offset.fromIntZeroExtend(slot << LOG_BYTES_IN_ADDRESS);
126      }
127    }