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.runtime;
014
015import static org.jikesrvm.runtime.JavaSizeConstants.BITS_IN_INT;
016import static org.jikesrvm.runtime.JavaSizeConstants.BYTES_IN_INT;
017import static org.jikesrvm.runtime.JavaSizeConstants.BYTES_IN_LONG;
018import static org.jikesrvm.runtime.JavaSizeConstants.LOG_BYTES_IN_INT;
019
020import org.jikesrvm.VM;
021import org.jikesrvm.compilers.common.CodeArray;
022import org.jikesrvm.mm.mminterface.Barriers;
023import org.jikesrvm.objectmodel.TIB;
024import org.jikesrvm.util.BitVector;
025import org.jikesrvm.util.ImmutableEntryIdentityHashMapRVM;
026import org.vmmagic.pragma.Uninterruptible;
027import org.vmmagic.pragma.UninterruptibleNoWarn;
028import org.vmmagic.unboxed.Address;
029import org.vmmagic.unboxed.Extent;
030import org.vmmagic.unboxed.Offset;
031import org.vmmagic.unboxed.Word;
032
033/**
034 * The static fields and methods comprising a running virtual machine image.
035 *
036 * <p> These fields, methods and literal constants form the "root set"
037 * of all the objects in the running virtual machine. They are stored
038 * in an array where the middle element is always pointed to by the
039 * virtual machine's "table of contents" (JTOC) register. The slots of
040 * this array hold either primitives (int, long, float, double),
041 * object pointers, or array pointers. To enable the garbage collector
042 * to differentiate between reference and non-reference values,
043 * reference values are indexed positively and numeric values
044 * negatively with respect to the middle of the table.
045 *
046 * <p> Consider the following declarations:
047 *
048 * <pre>
049 *      class A { static int    i = 123;    }
050 *      class B { static String s = "abc";  }
051 *      class C { static double d = 4.56;   }
052 *      class D { static void m() {} }
053 * </pre>
054 *
055 * <p>Here's a picture of what the corresponding JTOC would look like
056 * in memory:
057 *
058 * <pre>
059 *                     +---------------+
060 *                     |     ...       |
061 *                     +---------------+
062 * field            -6 |   C.d (hi)    |
063 *                     +---------------+
064 * field            -5 |   C.d (lo)    |
065 *                     +---------------+
066 * literal          -4 |  4.56 (hi)    |
067 *                     +---------------+
068 * literal          -3 |  4.56 (lo)    |
069 *                     +---------------+
070 * field            -2 |     A.i       |
071 *                     +---------------+
072 * literal          -1 |     123       |
073 *                     +---------------+       +---------------+
074 * [jtoc register]-&gt; 0:|      0        |       |   (header)    |
075 *                     +---------------+       +---------------+
076 * literal           1:|  (objref)   ---------&gt;|    "abc"      |
077 *                     +---------------+       +---------------+
078 * field             2:|     B.s       |
079 *                     +---------------+       +---------------+
080 *                   3:|  (coderef)  ------+   |   (header)    |
081 *                     +---------------+   |   +---------------+
082 *                     |     ...       |   +--&gt;|  machine code |
083 *                     +---------------+       |    for "m"    |
084 *                                             +---------------+
085 * </pre>
086 */
087public class Statics {
088  /**
089   * How many 32bit slots do we want in the JTOC to hold numeric (non-reference) values?
090   */
091  private static final int numNumericSlots =   0x20000; // 128k
092
093  /**
094   * How many reference-sized slots do we want in the JTOC to hold reference values?
095   */
096  private static final int numReferenceSlots = 0x20000; // 128k
097
098  /**
099   * Static data values (pointed to by JTOC register).
100   * This is currently fixed-size, although at one point the system's plans
101   * called for making it dynamically growable.  We could also make it
102   * non-contiguous.
103   */
104  private static final int[] slots = new int[numNumericSlots + (VM.BuildFor64Addr ? 2 : 1) * numReferenceSlots];
105
106  /**
107   * Object version of the slots used during boot image creation and
108   * destroyed shortly after. This is required to support conversion
109   * of a slot address to its associated object during boot image
110   * creation.
111   */
112  private static Object[] objectSlots = new Object[slots.length];
113
114  /**
115   * The logical middle of the table, references are slots above this and
116   * numeric values below this. The JTOC points to the middle of the
117   * table.
118   */
119  public static final int middleOfTable = numNumericSlots;
120
121  /** Next available numeric slot number */
122  private static volatile int nextNumericSlot = middleOfTable - 1;
123
124  /**
125   * Numeric slot hole. Holes are created to align 8byte values. We
126   * allocate into a hole rather than consume another numeric slot.
127   * The value of middleOfTable indicates the slot isn't in use.
128   */
129  private static volatile int numericSlotHole = middleOfTable;
130
131  /** Next available reference slot number */
132  private static volatile int nextReferenceSlot = middleOfTable;
133
134  /**
135   * Bit vector indicating whether a numeric slot is a field (true) or a
136   * literal (false).
137   */
138  private static final BitVector numericFieldVector = new BitVector(middleOfTable);
139
140  /**
141   * Map of objects to their literal offsets
142   */
143  private static final ImmutableEntryIdentityHashMapRVM<Object, Integer> objectLiterals =
144    new ImmutableEntryIdentityHashMapRVM<Object, Integer>();
145
146  static {
147    // allocate a slot to be null - offset zero should map to null
148    int offset = allocateReferenceSlot(false).toInt();
149    if (VM.VerifyAssertions) VM._assert(offset == 0);
150  }
151
152  /**
153   * Conversion from JTOC slot index to JTOC offset.
154   *
155   * @param slot the JTOC slot index
156   * @return the JTOC offset
157   */
158  @Uninterruptible
159  public static Offset slotAsOffset(int slot) {
160    return Offset.fromIntSignExtend((slot - middleOfTable) << LOG_BYTES_IN_INT);
161  }
162
163  /**
164   * Conversion from JTOC offset to JTOC slot index.
165   *
166   * @param offset the JTOC offset
167   * @return the JTOC slot index
168   */
169  @Uninterruptible
170  public static int offsetAsSlot(Offset offset) {
171    if (VM.VerifyAssertions) VM._assert((offset.toInt() & 3) == 0);
172    return middleOfTable + (offset.toInt() >> LOG_BYTES_IN_INT);
173  }
174
175  /**
176   * @return the lowest slot number in use
177   */
178  public static int getLowestInUseSlot() {
179    return nextNumericSlot + 1;
180  }
181
182  /**
183   * @return the highest slot number in use
184   */
185  public static int getHighestInUseSlot() {
186    return nextReferenceSlot - (VM.BuildFor32Addr ? 1 : 2);
187  }
188
189  /**
190   * Find the given literal in the int like literal map, if not found
191   * create a slot for the literal and place an entry in the map
192   * @param literal the literal value to find or create
193   * @return the offset in the JTOC of the literal
194   */
195  public static int findOrCreateIntSizeLiteral(int literal) {
196    final int bottom = getLowestInUseSlot();
197    final int top = middleOfTable;
198    for (int i = top; i >= bottom; i--) {
199      if ((slots[i] == literal) && !numericFieldVector.get(i) && (i != numericSlotHole)) {
200        return slotAsOffset(i).toInt();
201      }
202    }
203    Offset newOff = allocateNumericSlot(BYTES_IN_INT, false);
204    setSlotContents(newOff, literal);
205    return newOff.toInt();
206  }
207
208  /**
209   * Find the given literal in the long like literal map, if not found
210   * create a slot for the literal and place an entry in the map
211   * @param literal the literal value to find or create
212   * @return the offset in the JTOC of the literal
213   */
214  public static int findOrCreateLongSizeLiteral(long literal) {
215    final int bottom = getLowestInUseSlot();
216    final int top = middleOfTable & 0xFFFFFFFE;
217    for (int i = top; i >= bottom; i -= 2) {
218      Offset off = slotAsOffset(i);
219      if ((getSlotContentsAsLong(off) == literal) &&
220          !numericFieldVector.get(i) && !(numericFieldVector.get(i + 1)) &&
221          (i != numericSlotHole) && (i + 1 != numericSlotHole)) {
222        return slotAsOffset(i).toInt();
223      }
224    }
225    Offset newOff = allocateNumericSlot(BYTES_IN_LONG, false);
226    setSlotContents(newOff, literal);
227    return newOff.toInt();
228  }
229
230  /**
231   * Find the given literal in the 16byte like literal map, if not found
232   * create a slot for the literal and place an entry in the map
233   * @param literal_high the high part of the literal value to find or create
234   * @param literal_low the low part of the literal value to find or create
235   * @return the offset in the JTOC of the literal
236   */
237  public static int findOrCreate16ByteSizeLiteral(long literal_high, long literal_low) {
238    final int bottom = getLowestInUseSlot();
239    final int top = middleOfTable & 0xFFFFFFFC;
240    for (int i = top; i >= bottom; i -= 4) {
241      Offset off = slotAsOffset(i);
242      if ((getSlotContentsAsLong(off) == literal_low) &&
243          (getSlotContentsAsLong(off.plus(8)) == literal_high) &&
244          !numericFieldVector.get(i) && !(numericFieldVector.get(i + 1)) &&
245          !numericFieldVector.get(i + 2) && !(numericFieldVector.get(i + 3)) &&
246          (i != numericSlotHole) && (i + 1 != numericSlotHole) &&
247          (i + 2 != numericSlotHole) && (i + 3 != numericSlotHole)) {
248        return slotAsOffset(i).toInt();
249      }
250    }
251    Offset newOff = allocateNumericSlot(16, false);
252    setSlotContents(newOff, literal_low);
253    setSlotContents(newOff.plus(8), literal_high);
254    return newOff.toInt();
255  }
256
257  /**
258   * Find or allocate a slot in the JTOC for an object literal.
259   * @param       literal value
260   * @return offset of slot that was allocated
261   * Side effect: literal value is stored into JTOC
262   */
263  public static int findOrCreateObjectLiteral(Object literal) {
264    int off = findObjectLiteral(literal);
265    if (off != 0) {
266      return off;
267    } else {
268      Offset newOff = allocateReferenceSlot(false);
269      setSlotContents(newOff, literal);
270      synchronized (objectLiterals) {
271        objectLiterals.put(literal, newOff.toInt());
272      }
273      return newOff.toInt();
274    }
275  }
276
277  /**
278   * Find a slot in the JTOC with this object literal in else return 0
279   * @param  literal value
280   * @return offset containing literal or 0
281   */
282  public static int findObjectLiteral(Object literal) {
283    synchronized (objectLiterals) {
284      Integer result = objectLiterals.get(literal);
285      return result == null ? 0 : result.intValue();
286    }
287  }
288
289  /**
290   * Marks a slot that was previously a field as being a literal as its value is
291   * final.
292   *
293   * @param size the slot's size
294   * @param fieldOffset the field's offset in the JTOC
295   */
296  public static synchronized void markAsNumericLiteral(int size, Offset fieldOffset) {
297    int slot = offsetAsSlot(fieldOffset);
298    if (size == BYTES_IN_LONG) {
299      numericFieldVector.clear(slot);
300      numericFieldVector.clear(slot + 1);
301    } else {
302      numericFieldVector.clear(slot);
303    }
304  }
305
306  /**
307   * Marks a slot that was previously a field as being a literal as its value is
308   * final.
309   *
310   * @param fieldOffset the field's offset in the JTOC
311   */
312  public static synchronized void markAsReferenceLiteral(Offset fieldOffset) {
313    Object literal = getSlotContentsAsObject(fieldOffset);
314    if (!VM.runningVM && literal instanceof TIB) {
315      // TIB is just a wrapper for the boot image, so don't place the wrapper
316      // in objectLiterals
317      return;
318    } else if (literal != null) {
319      if (findObjectLiteral(literal) == 0) {
320        synchronized (objectLiterals) {
321          objectLiterals.put(literal, fieldOffset.toInt());
322        }
323      }
324    }
325  }
326
327  /**
328   * Allocate a numeric slot in the JTOC.
329   * @param size of slot
330   * @param field is the slot for a field
331   * @return offset of slot that was allocated as int
332   * (two slots are allocated for longs and doubles)
333   */
334  public static synchronized Offset allocateNumericSlot(int size, boolean field) {
335    // Result slot
336    int slot;
337    // Allocate 2 or 4 slots for wide items after possibly blowing
338    // other slots for alignment.
339    if (size == 16) {
340      // widen for a wide
341      nextNumericSlot -= 3;
342      // check alignment
343      if ((nextNumericSlot & 1) != 0) {
344        // slot isn't 8byte aligned so increase by 1 and record hole
345        nextNumericSlot--;
346        numericSlotHole = nextNumericSlot + 4;
347      }
348      if ((nextNumericSlot & 3) != 0) {
349        // slot not 16byte aligned, ignore any holes
350        nextNumericSlot -= 2;
351      }
352      // Remember the slot and adjust the next available slot
353      slot = nextNumericSlot;
354      nextNumericSlot--;
355      if (field) {
356        numericFieldVector.set(slot);
357        numericFieldVector.set(slot + 1);
358        numericFieldVector.set(slot + 2);
359        numericFieldVector.set(slot + 3);
360      }
361    } else if (size == BYTES_IN_LONG) {
362      // widen for a wide
363      nextNumericSlot--;
364      // check alignment
365      if ((nextNumericSlot & 1) != 0) {
366        // slot isn't 8byte aligned so increase by 1 and record hole
367        nextNumericSlot--;
368        numericSlotHole = nextNumericSlot + 2;
369      }
370      // Remember the slot and adjust the next available slot
371      slot = nextNumericSlot;
372      nextNumericSlot--;
373      if (field) {
374        numericFieldVector.set(slot);
375        numericFieldVector.set(slot + 1);
376      }
377    } else {
378      // 4byte quantity, try to reuse hole if one is available
379      if (numericSlotHole != middleOfTable) {
380        slot = numericSlotHole;
381        numericSlotHole = middleOfTable;
382      } else {
383        slot = nextNumericSlot;
384        nextNumericSlot--;
385      }
386      if (field) {
387        numericFieldVector.set(slot);
388      }
389    }
390    if (nextNumericSlot < 0) {
391      enlargeTable();
392    }
393    return slotAsOffset(slot);
394  }
395
396  /**
397   * Allocate a reference slot in the JTOC.
398   * @param field is the slot for a field
399   * @return offset of slot that was allocated as int
400   * (two slots are allocated on 64bit architectures)
401   */
402  public static synchronized Offset allocateReferenceSlot(boolean field) {
403    int slot = nextReferenceSlot;
404    nextReferenceSlot += getReferenceSlotSize();
405    if (nextReferenceSlot >= slots.length) {
406      enlargeTable();
407    }
408    return slotAsOffset(slot);
409  }
410
411  /**
412   * Grow the statics table
413   */
414  private static void enlargeTable() {
415    // !!TODO: enlarge slots[] and descriptions[], and modify JTOC register to
416    // point to newly enlarged slots[]
417    // NOTE: very tricky on IA32 because opt uses 32 bit literal address to access JTOC.
418    VM.sysFail("Statics.enlargeTable: jtoc is full");
419  }
420
421  /**
422   * @return number of numeric JTOC slots currently allocated.
423   */
424  @Uninterruptible
425  public static int getNumberOfNumericSlots() {
426    return middleOfTable - nextNumericSlot;
427  }
428
429  /**
430   * @return number of reference JTOC slots currently allocated.
431   */
432  @Uninterruptible
433  public static int getNumberOfReferenceSlots() {
434    return nextReferenceSlot - middleOfTable;
435  }
436
437  /**
438   * @return total number of slots comprising the JTOC.
439   */
440  @Uninterruptible
441  public static int getTotalNumberOfSlots() {
442    return slots.length;
443  }
444
445  /**
446   * Does specified JTOC slot contain a reference?
447   * @param  slot obtained from offsetAsSlot()
448   * @return {@code true} --&gt; slot contains a reference
449   */
450  @Uninterruptible
451  public static boolean isReference(int slot) {
452    return slot >= middleOfTable;
453  }
454
455  /**
456   * Does specified JTOC slot contain an int sized literal?
457   * @param  slot obtained from offsetAsSlot()
458   * @return {@code true} --&gt; slot contains a reference
459   */
460  public static boolean isIntSizeLiteral(int slot) {
461    if (isReference(slot) || slot < getLowestInUseSlot()) {
462      return false;
463    } else {
464      return !numericFieldVector.get(slot);
465    }
466  }
467
468  /**
469   * Does specified JTOC slot contain a long sized literal?
470   * @param  slot obtained from offsetAsSlot()
471   * @return {@code true} --&gt; slot contains a reference
472   */
473  public static boolean isLongSizeLiteral(int slot) {
474    if (isReference(slot) || slot < getLowestInUseSlot() || ((slot & 1) != 0)) {
475      return false;
476    } else {
477      return !numericFieldVector.get(slot) && !numericFieldVector.get(slot + 1);
478    }
479  }
480
481  /**
482   * Does specified JTOC slot contain a reference literal?
483   * @param  slot obtained from offsetAsSlot()
484   * @return {@code true} --&gt; slot contains a reference
485   */
486  public static boolean isReferenceLiteral(int slot) {
487    if (!isReference(slot) || slot > getHighestInUseSlot()) {
488      return false;
489    } else {
490      return (slotAsOffset(slot).toInt() == 0) ||
491        (findObjectLiteral(getSlotContentsAsObject(slotAsOffset(slot))) != 0);
492    }
493  }
494
495  /**
496   * @return size occupied by a reference
497   */
498  @Uninterruptible
499  public static int getReferenceSlotSize() {
500    return VM.BuildFor64Addr ? 2 : 1;
501  }
502
503  /**
504   * @return JTOC object (for JNI environment and GC).
505   */
506  @Uninterruptible
507  public static Address getSlots() {
508    return Magic.objectAsAddress(slots).plus(middleOfTable << LOG_BYTES_IN_INT);
509  }
510
511  /**
512   * @return JTOC object (for JNI environment and GC).
513   */
514  @Uninterruptible
515  public static int[] getSlotsAsIntArray() {
516    return slots;
517  }
518
519  /**
520   * @param offset the slot's offset in the JTOC
521   * @return contents of a slot, as an integer
522   */
523  @Uninterruptible
524  public static int getSlotContentsAsInt(Offset offset) {
525    if (VM.runningVM) {
526      return Magic.getIntAtOffset(slots, offset.plus(middleOfTable << LOG_BYTES_IN_INT));
527    } else {
528      int slot = offsetAsSlot(offset);
529      return slots[slot];
530    }
531  }
532
533  /**
534   * @param offset the slot's offset
535   * @return contents of a slot-pair, as a long integer.
536   */
537  @Uninterruptible
538  public static long getSlotContentsAsLong(Offset offset) {
539    if (VM.runningVM) {
540      return Magic.getLongAtOffset(slots, offset.plus(middleOfTable << LOG_BYTES_IN_INT));
541    } else {
542      int slot = offsetAsSlot(offset);
543      long result;
544      if (VM.LittleEndian) {
545        result = (((long) slots[slot + 1]) << BITS_IN_INT); // hi
546        result |= (slots[slot]) & 0xFFFFFFFFL; // lo
547      } else {
548        result = (((long) slots[slot]) << BITS_IN_INT);     // hi
549        result |= (slots[slot + 1]) & 0xFFFFFFFFL; // lo
550      }
551      return result;
552    }
553  }
554
555  /**
556   * @param offset the slot's offset
557   * @return contents of a slot, as an object.
558   */
559  @Uninterruptible
560  public static Object getSlotContentsAsObject(Offset offset) {
561    if (VM.runningVM) {
562      return Magic.getObjectAtOffset(slots, offset.plus(middleOfTable << LOG_BYTES_IN_INT));
563    } else {
564      return objectSlots[offsetAsSlot(offset)];
565    }
566  }
567
568  /**
569   * @param offset the slot's offset
570   * @return contents of a slot, as an Address.
571   */
572  @UninterruptibleNoWarn("Interruptible code only reachable during boot image creation")
573  public static Address getSlotContentsAsAddress(Offset offset) {
574    if (VM.runningVM) {
575      if (VM.BuildFor32Addr) {
576        return Address.fromIntSignExtend(getSlotContentsAsInt(offset));
577      } else {
578        return Address.fromLong(getSlotContentsAsLong(offset));
579      }
580    } else {
581      // Addresses are represented by objects in the tools building the VM
582      Object unboxed = objectSlots[offsetAsSlot(offset)];
583      if (unboxed instanceof Address) {
584        return (Address) unboxed;
585      } else if (unboxed instanceof Word) {
586        return ((Word) unboxed).toAddress();
587      } else if (unboxed instanceof Extent) {
588        return ((Extent) unboxed).toWord().toAddress();
589      } else if (unboxed instanceof Offset) {
590        return ((Offset) unboxed).toWord().toAddress();
591      } else {
592        if (VM.VerifyAssertions) VM._assert(VM.NOT_REACHED);
593        return Address.zero();
594      }
595    }
596  }
597
598  /**
599   * Set contents of a slot, as an integer.
600   *
601   * @param offset the slot's offset
602   * @param value new value for the slot
603   */
604  @Uninterruptible
605  public static void setSlotContents(Offset offset, int value) {
606    if (VM.runningVM) {
607      Magic.setIntAtOffset(slots, offset.plus(middleOfTable << LOG_BYTES_IN_INT), value);
608    } else {
609      slots[offsetAsSlot(offset)] = value;
610    }
611  }
612
613  /**
614   * Set contents of a slot, as an float.
615   *
616   * @param offset the slot's offset
617   * @param value new value for the slot
618   */
619  @Uninterruptible
620  public static void setSlotContents(Offset offset, float value) {
621    if (VM.runningVM) {
622      Magic.setFloatAtOffset(slots, offset.plus(middleOfTable << LOG_BYTES_IN_INT), value);
623    } else {
624      slots[offsetAsSlot(offset)] = Magic.floatAsIntBits(value);
625    }
626  }
627
628  /**
629   * Set contents of a slot, as a double.
630   *
631   * @param offset the slot's offset
632   * @param value new value for the slot
633   */
634  @Uninterruptible
635  public static void setSlotContents(Offset offset, double value) {
636    if (VM.runningVM) {
637      Magic.setDoubleAtOffset(slots, offset.plus(middleOfTable << LOG_BYTES_IN_INT), value);
638    } else {
639      int slot = offsetAsSlot(offset);
640      long value64bits = Magic.doubleAsLongBits(value);
641      if (VM.LittleEndian) {
642        slots[slot + 1] = (int) (value64bits >>> BITS_IN_INT); // hi
643        slots[slot] = (int) (value64bits); // lo
644      } else {
645        slots[slot] = (int) (value64bits >>> BITS_IN_INT); // hi
646        slots[slot + 1] = (int) (value64bits); // lo
647      }
648    }
649  }
650
651  /**
652   * Set contents of a slot, as a long integer.
653   *
654   * @param offset the slot's offset
655   * @param value new value for the slot
656   */
657  @Uninterruptible
658  public static void setSlotContents(Offset offset, long value) {
659    if (VM.runningVM) {
660      Magic.setLongAtOffset(slots, offset.plus(middleOfTable << LOG_BYTES_IN_INT), value);
661    } else {
662      int slot = offsetAsSlot(offset);
663      if (VM.LittleEndian) {
664        slots[slot + 1] = (int) (value >>> BITS_IN_INT); // hi
665        slots[slot] = (int) (value); // lo
666      } else {
667        slots[slot] = (int) (value >>> BITS_IN_INT); // hi
668        slots[slot + 1] = (int) (value); // lo
669      }
670    }
671  }
672
673  /**
674   * Set contents of a slot, as an object.
675   *
676   * @param offset the slot's offset
677   * @param object new value for the slot
678   */
679  @UninterruptibleNoWarn("Interruptible code only reachable during boot image creation")
680  public static void setSlotContents(Offset offset, Object object) {
681    // NB uninterruptible warnings are disabled for this method due to
682    // the array store which could cause a fault - this can't actually
683    // happen as the fault would only ever occur when not running the
684    // VM. We suppress the warning as we know the error can't happen.
685
686    if (VM.runningVM && Barriers.NEEDS_OBJECT_PUTSTATIC_BARRIER) {
687      Barriers.objectStaticWrite(object, offset, 0);
688    } else {
689      setSlotContents(offset, Magic.objectAsAddress(object).toWord());
690    }
691    if (VM.VerifyAssertions) VM._assert(offset.toInt() > 0);
692    if (!VM.runningVM && objectSlots != null) {
693      // When creating the boot image objectSlots is populated as
694      // Magic won't work in the bootstrap JVM.
695      objectSlots[offsetAsSlot(offset)] = Magic.bootImageIntern(object);
696    }
697  }
698
699  /**
700   * Set contents of a slot, as a CodeArray.
701   *
702   * @param offset the slot's offset
703   * @param code  new value for the slot
704   */
705  @Uninterruptible
706  public static void setSlotContents(Offset offset, CodeArray code) {
707    setSlotContents(offset, Magic.codeArrayAsObject(code));
708  }
709
710  /**
711   * Set contents of a slot, as a TIB.
712   *
713   * @param offset the slot's offset
714   * @param tib new value for the slot
715   */
716  @Uninterruptible
717  public static void setSlotContents(Offset offset, TIB tib) {
718    setSlotContents(offset, Magic.tibAsObject(tib));
719  }
720
721  /**
722   * Set contents of a slot, as a Word.
723   *
724   * @param offset the slot's offset
725   * @param word new value for the slot
726   */
727  @Uninterruptible
728  public static void setSlotContents(Offset offset, Word word) {
729    if (VM.runningVM) {
730      Magic.setWordAtOffset(slots, offset.plus(middleOfTable << LOG_BYTES_IN_INT), word);
731    } else {
732      if (VM.BuildFor32Addr) {
733        setSlotContents(offset, word.toInt());
734      } else {
735        setSlotContents(offset, word.toLong());
736      }
737    }
738  }
739
740  /**
741   * Set contents of a slot, as a Address
742   *
743   * @param offset the slot's offset
744   * @param value new value for the slot
745   */
746  @Uninterruptible
747  public static void setSlotContents(Offset offset, Address value) {
748    if (VM.runningVM) {
749      Magic.setAddressAtOffset(slots, offset.plus(middleOfTable << LOG_BYTES_IN_INT), value);
750    } else {
751      if (VM.BuildFor32Addr) {
752        setSlotContents(offset, value.toInt());
753      } else {
754        setSlotContents(offset, value.toLong());
755      }
756    }
757  }
758
759  /**
760   * Set contents of a slot, as a Extent
761   *
762   * @param offset the slot's offset
763   * @param value new value for the slot
764   */
765  @Uninterruptible
766  public static void setSlotContents(Offset offset, Extent value) {
767    if (VM.runningVM) {
768      Magic.setExtentAtOffset(slots, offset.plus(middleOfTable << LOG_BYTES_IN_INT), value);
769    } else {
770      if (VM.BuildFor32Addr) {
771        setSlotContents(offset, value.toInt());
772      } else {
773        setSlotContents(offset, value.toLong());
774      }
775    }
776  }
777
778  /**
779   * Set contents of a slot, as a Offset
780   *
781   * @param offset the slot's offset
782   * @param value new value for the slot
783   */
784  @Uninterruptible
785  public static void setSlotContents(Offset offset, Offset value) {
786    if (VM.runningVM) {
787      Magic.setOffsetAtOffset(slots, offset.plus(middleOfTable << LOG_BYTES_IN_INT), value);
788    } else {
789      if (VM.BuildFor32Addr) {
790        setSlotContents(offset, value.toInt());
791      } else {
792        setSlotContents(offset, value.toLong());
793      }
794    }
795  }
796
797  /**
798   * Inform Statics that boot image instantiation is over and that
799   * unnecessary data structures, for runtime, can be released.
800   * @return information that may later be restored to help generate
801   * the boot image report
802   */
803  public static Object bootImageInstantiationFinished() {
804    Object t = objectSlots;
805    objectSlots = null;
806    return t;
807  }
808
809  /**
810   * After serializing Statics the boot image writer generates
811   * a report. This method is called to restore data lost by the call
812   * to bootImageInstantiationFinished.
813   * @param slots object slots to restore
814   */
815  public static void bootImageReportGeneration(Object slots) {
816    objectSlots = (Object[])slots;
817  }
818}