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    }