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