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