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    }