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