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.objectmodel; 014 015import static org.jikesrvm.objectmodel.TIBLayoutConstants.*; 016import static org.jikesrvm.runtime.JavaSizeConstants.LOG_BITS_IN_BYTE; 017import static org.jikesrvm.runtime.JavaSizeConstants.LOG_BYTES_IN_INT; 018import static org.jikesrvm.runtime.UnboxedSizeConstants.BYTES_IN_ADDRESS; 019import static org.jikesrvm.runtime.UnboxedSizeConstants.LOG_BYTES_IN_ADDRESS; 020 021import org.jikesrvm.VM; 022import org.jikesrvm.architecture.ArchConstants; 023import org.jikesrvm.classloader.RVMType; 024import org.jikesrvm.compilers.common.CodeArray; 025import org.jikesrvm.compilers.common.LazyCompilationTrampoline; 026import org.jikesrvm.runtime.Magic; 027import org.vmmagic.Intrinsic; 028import org.vmmagic.pragma.Inline; 029import org.vmmagic.pragma.Interruptible; 030import org.vmmagic.pragma.NoInline; 031import org.vmmagic.pragma.NonMoving; 032import org.vmmagic.pragma.Uninterruptible; 033import org.vmmagic.pragma.UninterruptibleNoWarn; 034import org.vmmagic.unboxed.Address; 035import org.vmmagic.unboxed.Offset; 036import org.vmmagic.unboxed.Word; 037 038/** 039 * This class represents an instance of a type information block, at runtime it 040 * is an array with Object elements. 041 * @see TIBLayoutConstants 042 */ 043@Uninterruptible 044@NonMoving 045public final class TIB implements RuntimeTable<Object> { 046 /** 047 * @return the number of words required to hold the lazy method invoker trampoline. 048 */ 049 public static int lazyMethodInvokerTrampolineWords() { 050 int codeWords = VM.BuildForIA32 ? (VM.BuildFor32Addr ? 2 : 1) : (VM.BuildFor32Addr ? 3 : 2); 051 if (VM.VerifyAssertions && VM.runningVM) { 052 int codeBytes = LazyCompilationTrampoline.getInstructions().length() << ArchConstants.getLogInstructionWidth(); 053 VM._assert(codeWords == ((codeBytes + BYTES_IN_ADDRESS - 1) >>> LOG_BYTES_IN_ADDRESS)); 054 } 055 return codeWords; 056 } 057 058 /** Alignment encoded data for this TIB - only used at build time */ 059 private int alignData; 060 061 062 /** 063 * Calculates the size of a TIB. 064 * 065 * @param numVirtualMethods the number of virtual methods in the TIB 066 * @return the size of a TIB with the given number of virtual methods 067 */ 068 @NoInline 069 public static int computeSize(int numVirtualMethods) { 070 return TIB_FIRST_VIRTUAL_METHOD_INDEX + numVirtualMethods + lazyMethodInvokerTrampolineWords(); 071 } 072 073 /** 074 * Calculate the virtual method offset for the given index. 075 * @param virtualMethodIndex The index to calculate the offset for 076 * @return The offset. 077 */ 078 public static Offset getVirtualMethodOffset(int virtualMethodIndex) { 079 return Offset.fromIntZeroExtend((TIB_FIRST_VIRTUAL_METHOD_INDEX + virtualMethodIndex) << LOG_BYTES_IN_ADDRESS); 080 } 081 082 /** 083 * Calculate the virtual method index for the given offset. 084 * @param virtualMethodOffset The offset to calculate the index for 085 * @return The index. 086 */ 087 public static int getVirtualMethodIndex(Offset virtualMethodOffset) { 088 return (virtualMethodOffset.toInt() >>> LOG_BYTES_IN_ADDRESS) - TIB_FIRST_VIRTUAL_METHOD_INDEX; 089 } 090 091 /** 092 * Calculate the virtual method index for the given raw slot index. 093 * 094 * @param slot The raw slot to find the virtual method index for. 095 * @return The index. 096 */ 097 public static int getVirtualMethodIndex(int slot) { 098 if (VM.VerifyAssertions) VM._assert(slot > TIB_FIRST_VIRTUAL_METHOD_INDEX); 099 return slot - TIB_FIRST_VIRTUAL_METHOD_INDEX; 100 } 101 102 /** 103 * The backing data used during boot image writing. 104 */ 105 private final Object[] data; 106 107 private TIB(int size) { 108 this.data = new Object[size]; 109 } 110 111 @Override 112 public Object[] getBacking() { 113 if (VM.VerifyAssertions) VM._assert(!VM.runningVM); 114 return data; 115 } 116 117 /** 118 * Create a new TIB of the specified size. 119 * 120 * @param size The size of the TIB 121 * @param alignData Alignment-encoded data for this TIB, 122 * AlignmentEncoding.ALIGN_CODE_NONE for no alignment encoding. 123 * @return The created TIB instance. 124 */ 125 @NoInline 126 @Interruptible 127 public static TIB allocate(int size, int alignData) { 128 if (VM.VerifyAssertions && VM.runningVM) VM._assert(VM.NOT_REACHED); 129 TIB tib = new TIB(size); 130 tib.setAlignData(alignData); 131 return tib; 132 } 133 134 /** 135 * Get a TIB entry. 136 * 137 * @param index The index of the entry to get 138 * @return The value of that entry 139 */ 140 @Override 141 @Intrinsic 142 public Object get(int index) { 143 if (VM.VerifyAssertions && VM.runningVM) VM._assert(VM.NOT_REACHED); 144 return data[index]; 145 } 146 147 /** 148 * Set a TIB entry. 149 * 150 * @param index The index of the entry to set 151 * @param value The value to set the entry to. 152 */ 153 @Override 154 @Intrinsic 155 @UninterruptibleNoWarn("Interruptible code not reachable at runtime") 156 public void set(int index, Object value) { 157 if (VM.VerifyAssertions && VM.runningVM) VM._assert(VM.NOT_REACHED); 158 data[index] = value; 159 } 160 161 /** 162 * @return the length of the TIB 163 */ 164 @Override 165 @Intrinsic 166 public int length() { 167 return data.length; 168 } 169 170 @Inline 171 public RVMType getType() { 172 if (VM.runningVM) { 173 return Magic.objectAsType(get(TIB_TYPE_INDEX)); 174 } else { 175 return (RVMType)get(TIB_TYPE_INDEX); 176 } 177 } 178 179 public void setType(RVMType type) { 180 set(TIB_TYPE_INDEX, type); 181 } 182 183 @Inline 184 public short[] getSuperclassIds() { 185 return Magic.objectAsShortArray(get(TIB_SUPERCLASS_IDS_INDEX)); 186 } 187 188 public void setSuperclassIds(short[] superclassIds) { 189 set(TIB_SUPERCLASS_IDS_INDEX, superclassIds); 190 } 191 192 @Interruptible 193 public ITableArray getITableArray() { 194 if (VM.VerifyAssertions) VM._assert(getType().isClassType()); 195 return (ITableArray)get(TIB_INTERFACE_DISPATCH_TABLE_INDEX); 196 } 197 198 public void setITableArray(ITableArray iTableArray) { 199 if (VM.VerifyAssertions) VM._assert(getType().isClassType()); 200 set(TIB_INTERFACE_DISPATCH_TABLE_INDEX, iTableArray); 201 } 202 203 @Inline 204 public int[] getDoesImplement() { 205 return Magic.objectAsIntArray(get(TIB_DOES_IMPLEMENT_INDEX)); 206 } 207 208 public void setDoesImplement(int[] doesImplement) { 209 set(TIB_DOES_IMPLEMENT_INDEX, doesImplement); 210 } 211 212 @Interruptible 213 public IMT getImt() { 214 if (VM.VerifyAssertions) VM._assert(getType().isClassType()); 215 return (IMT)get(TIB_INTERFACE_DISPATCH_TABLE_INDEX); 216 } 217 218 public void setImt(IMT imt) { 219 if (VM.VerifyAssertions) VM._assert(imt.length() == IMT_METHOD_SLOTS); 220 if (VM.VerifyAssertions) VM._assert(getType().isClassType()); 221 set(TIB_INTERFACE_DISPATCH_TABLE_INDEX, imt); 222 } 223 224 public void setArrayElementTib(TIB arrayElementTIB) { 225 if (VM.VerifyAssertions) VM._assert(getType().isArrayType()); 226 set(TIB_ARRAY_ELEMENT_TIB_INDEX, Magic.tibAsObject(arrayElementTIB)); 227 } 228 229 /** 230 * Gets a virtual method from this TIB. 231 * 232 * When running the VM, we must translate requests to return the internal 233 * lazy compilation trampoline marker. 234 * 235 * @param virtualMethodIndex the index of the virtual method 236 * @return the code for the virtual method or a lazy compilation trampoline 237 */ 238 @NoInline 239 @Interruptible 240 public CodeArray getVirtualMethod(int virtualMethodIndex) { 241 int index = TIB_FIRST_VIRTUAL_METHOD_INDEX + virtualMethodIndex; 242 if (VM.runningVM && isInternalLazyCompilationTrampoline(virtualMethodIndex)) { 243 return LazyCompilationTrampoline.getInstructions(); 244 } 245 return (CodeArray) get(index); 246 } 247 248 /** 249 * @param virtualMethodIndex the index of the virtual method 250 * @return whether a virtual method is the internal lazy compilation trampoline 251 */ 252 @NoInline 253 public boolean isInternalLazyCompilationTrampoline(int virtualMethodIndex) { 254 int index = TIB_FIRST_VIRTUAL_METHOD_INDEX + virtualMethodIndex; 255 Address tibAddress = Magic.objectAsAddress(this); 256 Address callAddress = tibAddress.loadAddress(Offset.fromIntZeroExtend(index << LOG_BYTES_IN_ADDRESS)); 257 Address maxAddress = tibAddress.plus(Offset.fromIntZeroExtend(length() << LOG_BYTES_IN_ADDRESS)); 258 return callAddress.GE(tibAddress) && callAddress.LT(maxAddress); 259 } 260 261 @Interruptible 262 public CodeArray getVirtualMethod(Offset virtualMethodOffset) { 263 return getVirtualMethod(getVirtualMethodIndex(virtualMethodOffset)); 264 } 265 266 /** 267 * Set a virtual method in this TIB. 268 * 269 * When running the VM, we must translate requests to use the internal 270 * lazy compilation trampoline. 271 * 272 * @param virtualMethodIndex the index of the virtual metho 273 * @param code the code for the virtual method 274 */ 275 @NoInline 276 public void setVirtualMethod(int virtualMethodIndex, CodeArray code) { 277 if (VM.VerifyAssertions) VM._assert(virtualMethodIndex >= 0); 278 279 if (VM.runningVM && code == LazyCompilationTrampoline.getInstructions()) { 280 Address tibAddress = Magic.objectAsAddress(this); 281 Address callAddress = tibAddress.plus(Offset.fromIntZeroExtend(lazyMethodInvokerTrampolineIndex() << LOG_BYTES_IN_ADDRESS)); 282 set(TIB_FIRST_VIRTUAL_METHOD_INDEX + virtualMethodIndex, callAddress); 283 } else { 284 set(TIB_FIRST_VIRTUAL_METHOD_INDEX + virtualMethodIndex, code); 285 } 286 } 287 288 public void setVirtualMethod(Offset virtualMethodOffset, CodeArray code) { 289 setVirtualMethod(getVirtualMethodIndex(virtualMethodOffset), code); 290 } 291 292 /** 293 * Calculate the address that is the call target for the lazy method invoker trampoline. 294 * @return the offset of the instruction that is the call target 295 */ 296 public int lazyMethodInvokerTrampolineIndex() { 297 return length() - lazyMethodInvokerTrampolineWords(); 298 } 299 300 /** 301 * Initialize the lazy method invoker trampoline for this tib. 302 */ 303 @NoInline 304 public void initializeInternalLazyCompilationTrampoline() { 305 CodeArray source = LazyCompilationTrampoline.getInstructions(); 306 int targetSlot = lazyMethodInvokerTrampolineIndex(); 307 int logIPW = LOG_BYTES_IN_ADDRESS - ArchConstants.getLogInstructionWidth(); 308 int logIPI = LOG_BYTES_IN_INT - ArchConstants.getLogInstructionWidth(); 309 if (VM.VerifyAssertions) VM._assert(ArchConstants.getLogInstructionWidth() <= LOG_BYTES_IN_INT); 310 int mask = 0xFFFFFFFF >>> (((1 << logIPI) - 1) << LOG_BITS_IN_BYTE); 311 for (int i = 0; i < lazyMethodInvokerTrampolineWords(); i++) { 312 Word currentWord = Word.zero(); 313 int base = i << logIPW; 314 for (int j = 0; j < (1 << logIPW) && (base + j) < source.length(); j++) { 315 Word currentEntry = Word.fromIntZeroExtend(source.get(base + j) & mask); 316 currentEntry = currentEntry.lsh(((VM.LittleEndian ? j : (1 << logIPW) - (j + 1)) << ArchConstants.getLogInstructionWidth()) << LOG_BITS_IN_BYTE); 317 currentWord = currentWord.or(currentEntry); 318 } 319 set(targetSlot + i, currentWord); 320 } 321 } 322 323 324 public void setSpecializedMethod(int specializedMethodIndex, CodeArray code) { 325 if (VM.VerifyAssertions) VM._assert(specializedMethodIndex >= 0); 326 set(TIB_FIRST_SPECIALIZED_METHOD_INDEX + specializedMethodIndex, code); 327 } 328 329 /** 330 * @return the number of virtual methods in this TIB. 331 */ 332 public int numVirtualMethods() { 333 return length() - TIB_FIRST_VIRTUAL_METHOD_INDEX - lazyMethodInvokerTrampolineWords(); 334 } 335 336 /** 337 * Does this slot in the TIB hold a TIB entry? 338 * @param slot the TIB slot 339 * @return {@code true} if this the array element TIB 340 */ 341 public boolean slotContainsTib(int slot) { 342 if (slot == TIB_ARRAY_ELEMENT_TIB_INDEX && getType().isArrayType()) { 343 if (VM.VerifyAssertions) VM._assert(get(slot) != null); 344 return true; 345 } 346 return false; 347 } 348 349 /** 350 * Does this slot in the TIB hold code? 351 * @param slot the TIB slot 352 * @return {@code true} if slot is one that holds a code array reference 353 */ 354 public boolean slotContainsCode(int slot) { 355 if (VM.VerifyAssertions) { 356 VM._assert(slot < length()); 357 } 358 return slot >= TIB_FIRST_VIRTUAL_METHOD_INDEX; 359 } 360 361 public void setAlignData(int alignData) { 362 this.alignData = alignData; 363 } 364 365 public int getAlignData() { 366 return alignData; 367 } 368}