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