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 & 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}