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 public String toString() {
094 return "{" + name + " " + descriptor + "}";
095 }
096
097 public int hashCode() {
098 return name.hashCode() + descriptor.hashCode();
099 }
100
101 public boolean equals(Object other) {
102 if (other instanceof InterfaceMethodSignature) {
103 InterfaceMethodSignature that = (InterfaceMethodSignature) other;
104 return name == that.name && descriptor == that.descriptor;
105 } else {
106 return false;
107 }
108 }
109
110 /**
111 * If using embedded IMTs, Get offset of interface method slot in TIB.
112 * If using indirect IMTs, Get offset of interface method slot in IMT.
113 * Note that all methods with same name & descriptor map to the same slot.
114 * <p>
115 * TODO!! replace this stupid offset assignment algorithm with something more reasonable.
116 *
117 * @return offset in TIB/IMT
118 */
119 public Offset getIMTOffset() {
120 if (VM.VerifyAssertions) VM._assert(VM.BuildForIMTInterfaceInvocation);
121 int slot = id % IMT_METHOD_SLOTS;
122 return Offset.fromIntZeroExtend(slot << LOG_BYTES_IN_ADDRESS);
123 }
124 }