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.mm.mmtk;
014    
015    import org.mmtk.utility.alloc.Allocator;
016    
017    import org.jikesrvm.runtime.Magic;
018    import org.jikesrvm.objectmodel.JavaHeaderConstants;
019    import org.jikesrvm.objectmodel.TIB;
020    import org.jikesrvm.classloader.Atom;
021    import org.jikesrvm.classloader.RVMArray;
022    import org.jikesrvm.classloader.RVMClass;
023    import org.jikesrvm.classloader.RVMType;
024    import org.jikesrvm.mm.mminterface.Selected;
025    import org.jikesrvm.mm.mminterface.DebugUtil;
026    import org.jikesrvm.mm.mminterface.MemoryManager;
027    
028    import org.vmmagic.unboxed.*;
029    import org.vmmagic.pragma.*;
030    
031    @Uninterruptible public final class ObjectModel extends org.mmtk.vm.ObjectModel implements org.mmtk.utility.Constants,
032                                                                                               org.jikesrvm.Constants {
033    
034      protected Offset getArrayBaseOffset() { return JavaHeaderConstants.ARRAY_BASE_OFFSET; }
035    
036      /**
037       * Copy an object using a plan's allocCopy to get space and install
038       * the forwarding pointer.  On entry, <code>from</code> must have
039       * been reserved for copying by the caller.  This method calls the
040       * plan's <code>getStatusForCopy()</code> method to establish a new
041       * status word for the copied object and <code>postCopy()</code> to
042       * allow the plan to perform any post copy actions.
043       *
044       * @param from the address of the object to be copied
045       * @return the address of the new object
046       */
047      @Inline
048      public ObjectReference copy(ObjectReference from, int allocator) {
049        TIB tib = org.jikesrvm.objectmodel.ObjectModel.getTIB(from);
050        RVMType type = Magic.objectAsType(tib.getType());
051    
052        if (type.isClassType())
053          return copyScalar(from, tib, type.asClass(), allocator);
054        else
055          return copyArray(from, tib, type.asArray(), allocator);
056      }
057    
058      @Inline
059      private ObjectReference copyScalar(ObjectReference from, TIB tib, RVMClass type, int allocator) {
060        int bytes = org.jikesrvm.objectmodel.ObjectModel.bytesRequiredWhenCopied(from.toObject(), type);
061        int align = org.jikesrvm.objectmodel.ObjectModel.getAlignment(type, from.toObject());
062        int offset = org.jikesrvm.objectmodel.ObjectModel.getOffsetForAlignment(type, from);
063        Selected.Collector plan = Selected.Collector.get();
064        allocator = plan.copyCheckAllocator(from, bytes, align, allocator);
065        Address region = MemoryManager.allocateSpace(plan, bytes, align, offset,
066                                                    allocator, from);
067        Object toObj = org.jikesrvm.objectmodel.ObjectModel.moveObject(region, from.toObject(), bytes, type);
068        ObjectReference to = ObjectReference.fromObject(toObj);
069        plan.postCopy(to, ObjectReference.fromObject(tib), bytes, allocator);
070        return to;
071      }
072    
073      @Inline
074      private ObjectReference copyArray(ObjectReference from, TIB tib, RVMArray type, int allocator) {
075        int elements = Magic.getArrayLength(from.toObject());
076        int bytes = org.jikesrvm.objectmodel.ObjectModel.bytesRequiredWhenCopied(from.toObject(), type, elements);
077        int align = org.jikesrvm.objectmodel.ObjectModel.getAlignment(type, from.toObject());
078        int offset = org.jikesrvm.objectmodel.ObjectModel.getOffsetForAlignment(type, from);
079        Selected.Collector plan = Selected.Collector.get();
080        allocator = plan.copyCheckAllocator(from, bytes, align, allocator);
081        Address region = MemoryManager.allocateSpace(plan, bytes, align, offset,
082                                                    allocator, from);
083        Object toObj = org.jikesrvm.objectmodel.ObjectModel.moveObject(region, from.toObject(), bytes, type);
084        ObjectReference to = ObjectReference.fromObject(toObj);
085        plan.postCopy(to, ObjectReference.fromObject(tib), bytes, allocator);
086        if (type == RVMType.CodeArrayType) {
087          // sync all moved code arrays to get icache and dcache in sync
088          // immediately.
089          int dataSize = bytes - org.jikesrvm.objectmodel.ObjectModel.computeHeaderSize(Magic.getObjectType(toObj));
090          org.jikesrvm.runtime.Memory.sync(to.toAddress(), dataSize);
091        }
092        return to;
093      }
094    
095      /**
096       * Return the size of a given object, in bytes
097       *
098       * @param object The object whose size is being queried
099       * @return The size (in bytes) of the given object.
100       */
101      static int getObjectSize(ObjectReference object) {
102        TIB tib = org.jikesrvm.objectmodel.ObjectModel.getTIB(object);
103        RVMType type = Magic.objectAsType(tib.getType());
104    
105        if (type.isClassType())
106          return org.jikesrvm.objectmodel.ObjectModel.bytesRequiredWhenCopied(object.toObject(), type.asClass());
107        else
108          return org.jikesrvm.objectmodel.ObjectModel.bytesRequiredWhenCopied(object.toObject(), type.asArray(), Magic.getArrayLength(object.toObject()));
109      }
110    
111      /**
112       * Copy an object to be pointer to by the to address. This is required
113       * for delayed-copy collectors such as compacting collectors. During the
114       * collection, MMTk reserves a region in the heap for an object as per
115       * requirements found from ObjectModel and then asks ObjectModel to
116       * determine what the object's reference will be post-copy.
117       *
118       * @param from the address of the object to be copied
119       * @param to The target location.
120       * @param region The start (or an address less than) the region that was reserved for this object.
121       * @return Address The address past the end of the copied object
122       */
123      @Inline
124      public Address copyTo(ObjectReference from, ObjectReference to, Address region) {
125        TIB tib = org.jikesrvm.objectmodel.ObjectModel.getTIB(from);
126        RVMType type = tib.getType();
127        int bytes;
128    
129        boolean copy = (from != to);
130    
131        if (copy) {
132          if (type.isClassType()) {
133            RVMClass classType = type.asClass();
134            bytes = org.jikesrvm.objectmodel.ObjectModel.bytesRequiredWhenCopied(from.toObject(), classType);
135            org.jikesrvm.objectmodel.ObjectModel.moveObject(from.toObject(), to.toObject(), bytes, classType);
136          } else {
137          RVMArray arrayType = type.asArray();
138            int elements = Magic.getArrayLength(from.toObject());
139            bytes = org.jikesrvm.objectmodel.ObjectModel.bytesRequiredWhenCopied(from.toObject(), arrayType, elements);
140            org.jikesrvm.objectmodel.ObjectModel.moveObject(from.toObject(), to.toObject(), bytes, arrayType);
141          }
142        } else {
143          bytes = getCurrentSize(to);
144        }
145    
146        Address start = org.jikesrvm.objectmodel.ObjectModel.objectStartRef(to);
147        Allocator.fillAlignmentGap(region, start);
148    
149        return start.plus(bytes);
150      }
151    
152      /**
153       * Return the reference that an object will be refered to after it is copied
154       * to the specified region. Used in delayed-copy collectors such as compacting
155       * collectors.
156       *
157       * @param from The object to be copied.
158       * @param to The region to be copied to.
159       * @return The resulting reference.
160       */
161      public ObjectReference getReferenceWhenCopiedTo(ObjectReference from, Address to) {
162        return ObjectReference.fromObject(org.jikesrvm.objectmodel.ObjectModel.getReferenceWhenCopiedTo(from.toObject(), to));
163      }
164    
165      /**
166       * Gets a pointer to the address just past the end of the object.
167       *
168       * @param object The objecty.
169       */
170      public Address getObjectEndAddress(ObjectReference object) {
171        return org.jikesrvm.objectmodel.ObjectModel.getObjectEndAddress(object.toObject());
172      }
173    
174      /**
175       * Return the size required to copy an object
176       *
177       * @param object The object whose size is to be queried
178       * @return The size required to copy <code>obj</code>
179       */
180      public int getSizeWhenCopied(ObjectReference object) {
181        return org.jikesrvm.objectmodel.ObjectModel.bytesRequiredWhenCopied(object.toObject());
182      }
183    
184      /**
185       * Return the alignment requirement for a copy of this object
186       *
187       * @param object The object whose size is to be queried
188       * @return The alignment required for a copy of <code>obj</code>
189       */
190      public int getAlignWhenCopied(ObjectReference object) {
191        TIB tib = org.jikesrvm.objectmodel.ObjectModel.getTIB(object);
192        RVMType type = tib.getType();
193        if (type.isArrayType()) {
194          return org.jikesrvm.objectmodel.ObjectModel.getAlignment(type.asArray(), object.toObject());
195        } else {
196          return org.jikesrvm.objectmodel.ObjectModel.getAlignment(type.asClass(), object.toObject());
197        }
198      }
199    
200      /**
201       * Return the alignment offset requirements for a copy of this object
202       *
203       * @param object The object whose size is to be queried
204       * @return The alignment offset required for a copy of <code>obj</code>
205       */
206      public int getAlignOffsetWhenCopied(ObjectReference object) {
207        TIB tib = org.jikesrvm.objectmodel.ObjectModel.getTIB(object);
208        RVMType type = tib.getType();
209        if (type.isArrayType()) {
210          return org.jikesrvm.objectmodel.ObjectModel.getOffsetForAlignment(type.asArray(), object);
211        } else {
212          return org.jikesrvm.objectmodel.ObjectModel.getOffsetForAlignment(type.asClass(), object);
213        }
214      }
215    
216      /**
217       * Return the size used by an object
218       *
219       * @param object The object whose size is to be queried
220       * @return The size of <code>obj</code>
221       */
222      public int getCurrentSize(ObjectReference object) {
223        return org.jikesrvm.objectmodel.ObjectModel.bytesUsed(object.toObject());
224      }
225    
226      /**
227       * Return the next object in the heap under contiguous allocation
228       */
229      public ObjectReference getNextObject(ObjectReference object) {
230        return org.jikesrvm.objectmodel.ObjectModel.getNextObject(object);
231      }
232    
233      /**
234       * Return an object reference from knowledge of the low order word
235       */
236      public ObjectReference getObjectFromStartAddress(Address start) {
237        return org.jikesrvm.objectmodel.ObjectModel.getObjectFromStartAddress(start);
238      }
239    
240      /**
241       * Get the type descriptor for an object.
242       *
243       * @param ref address of the object
244       * @return byte array with the type descriptor
245       */
246      public byte [] getTypeDescriptor(ObjectReference ref) {
247        Atom descriptor = Magic.getObjectType(ref).getDescriptor();
248        return descriptor.toByteArray();
249      }
250    
251      @Inline
252      public int getArrayLength(ObjectReference object) {
253        return Magic.getArrayLength(object.toObject());
254      }
255    
256      /**
257       * Is the passed object an array?
258       *
259       * @param object address of the object
260       */
261      public boolean isArray(ObjectReference object) {
262        return org.jikesrvm.objectmodel.ObjectModel.getObjectType(object.toObject()).isArrayType();
263      }
264    
265      /**
266       * Is the passed object a primitive array?
267       *
268       * @param object address of the object
269       */
270      public boolean isPrimitiveArray(ObjectReference object) {
271        Object obj = object.toObject();
272        return (obj instanceof long[]   ||
273                obj instanceof int[]    ||
274                obj instanceof short[]  ||
275                obj instanceof byte[]   ||
276                obj instanceof double[] ||
277                obj instanceof float[]);
278      }
279    
280      /**
281       * Tests a bit available for memory manager use in an object.
282       *
283       * @param object the address of the object
284       * @param idx the index of the bit
285       */
286      public boolean testAvailableBit(ObjectReference object, int idx) {
287        return org.jikesrvm.objectmodel.ObjectModel.testAvailableBit(object.toObject(), idx);
288      }
289    
290      /**
291       * Sets a bit available for memory manager use in an object.
292       *
293       * @param object the address of the object
294       * @param idx the index of the bit
295       * @param flag <code>true</code> to set the bit to 1,
296       * <code>false</code> to set it to 0
297       */
298      public void setAvailableBit(ObjectReference object, int idx,
299                                         boolean flag) {
300        org.jikesrvm.objectmodel.ObjectModel.setAvailableBit(object.toObject(), idx, flag);
301      }
302    
303      /**
304       * Attempts to set the bits available for memory manager use in an
305       * object.  The attempt will only be successful if the current value
306       * of the bits matches <code>oldVal</code>.  The comparison with the
307       * current value and setting are atomic with respect to other
308       * allocators.
309       *
310       * @param object the address of the object
311       * @param oldVal the required current value of the bits
312       * @param newVal the desired new value of the bits
313       * @return <code>true</code> if the bits were set,
314       * <code>false</code> otherwise
315       */
316      public boolean attemptAvailableBits(ObjectReference object,
317                                                 Word oldVal, Word newVal) {
318        return org.jikesrvm.objectmodel.ObjectModel.attemptAvailableBits(object.toObject(), oldVal,
319                                                   newVal);
320      }
321    
322      /**
323       * Gets the value of bits available for memory manager use in an
324       * object, in preparation for setting those bits.
325       *
326       * @param object the address of the object
327       * @return the value of the bits
328       */
329      public Word prepareAvailableBits(ObjectReference object) {
330        return org.jikesrvm.objectmodel.ObjectModel.prepareAvailableBits(object.toObject());
331      }
332    
333      /**
334       * Sets the byte available for memory manager use in an object.
335       *
336       * @param object the address of the object
337       * @param val the new value of the byte
338       */
339      public void writeAvailableByte(ObjectReference object, byte val) {
340        org.jikesrvm.objectmodel.ObjectModel.writeAvailableByte(object.toObject(), val);
341      }
342    
343      /**
344       * Read the byte available for memory manager use in an object.
345       *
346       * @param object the address of the object
347       * @return the value of the byte
348       */
349      public byte readAvailableByte(ObjectReference object) {
350        return org.jikesrvm.objectmodel.ObjectModel.readAvailableByte(object.toObject());
351      }
352    
353      /**
354       * Sets the bits available for memory manager use in an object.
355       *
356       * @param object the address of the object
357       * @param val the new value of the bits
358       */
359      public void writeAvailableBitsWord(ObjectReference object, Word val) {
360        org.jikesrvm.objectmodel.ObjectModel.writeAvailableBitsWord(object.toObject(), val);
361      }
362    
363      /**
364       * Read the bits available for memory manager use in an object.
365       *
366       * @param object the address of the object
367       * @return the value of the bits
368       */
369      public Word readAvailableBitsWord(ObjectReference object) {
370        return org.jikesrvm.objectmodel.ObjectModel.readAvailableBitsWord(object.toObject());
371      }
372    
373      /**
374       * Gets the offset of the memory management header from the object
375       * reference address.  XXX The object model / memory manager
376       * interface should be improved so that the memory manager does not
377       * need to know this.
378       *
379       * @return the offset, relative the object reference address
380       */
381      /* AJG: Should this be a variable rather than method? */
382      public Offset GC_HEADER_OFFSET() {
383        return org.jikesrvm.objectmodel.ObjectModel.GC_HEADER_OFFSET;
384      }
385    
386      /**
387       * Returns the lowest address of the storage associated with an object.
388       *
389       * @param object the reference address of the object
390       * @return the lowest address of the object
391       */
392      @Inline
393      public Address objectStartRef(ObjectReference object) {
394        return org.jikesrvm.objectmodel.ObjectModel.objectStartRef(object);
395      }
396    
397      /**
398       * Returns an address guaranteed to be inside the storage assocatied
399       * with and object.
400       *
401       * @param object the reference address of the object
402       * @return an address inside the object
403       */
404      public Address refToAddress(ObjectReference object) {
405        return org.jikesrvm.objectmodel.ObjectModel.getPointerInMemoryRegion(object);
406      }
407    
408      /**
409       * Checks if a reference of the given type in another object is
410       * inherently acyclic.  The type is given as a TIB.
411       *
412       * @return <code>true</code> if a reference of the type is
413       * inherently acyclic
414       */
415      @Inline
416      public boolean isAcyclic(ObjectReference typeRef) {
417        TIB tib = Magic.addressAsTIB(typeRef.toAddress());
418        RVMType type = tib.getType();
419        return type.isAcyclicReference();
420      }
421    
422      /**
423       * Dump debugging information for an object.
424       *
425       * @param object The object whose information is to be dumped
426       */
427      public void dumpObject(ObjectReference object) {
428        DebugUtil.dumpRef(object);
429      }
430    }
431