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.mm.mmtk;
014
015import static org.jikesrvm.objectmodel.JavaHeaderConstants.ARRAY_BASE_OFFSET;
016import static org.jikesrvm.objectmodel.JavaHeaderConstants.GC_HEADER_OFFSET;
017
018import org.jikesrvm.classloader.Atom;
019import org.jikesrvm.classloader.RVMArray;
020import org.jikesrvm.classloader.RVMClass;
021import org.jikesrvm.classloader.RVMType;
022import org.jikesrvm.mm.mminterface.DebugUtil;
023import org.jikesrvm.mm.mminterface.MemoryManager;
024import org.jikesrvm.objectmodel.TIB;
025import org.jikesrvm.runtime.Magic;
026import org.mmtk.plan.CollectorContext;
027import org.mmtk.utility.alloc.Allocator;
028import org.mmtk.vm.VM;
029import org.vmmagic.pragma.Inline;
030import org.vmmagic.pragma.Uninterruptible;
031import org.vmmagic.unboxed.Address;
032import org.vmmagic.unboxed.ObjectReference;
033import org.vmmagic.unboxed.Offset;
034import org.vmmagic.unboxed.Word;
035
036@Uninterruptible public final class ObjectModel extends org.mmtk.vm.ObjectModel {
037
038  @Override
039  protected Offset getArrayBaseOffset() {
040    return ARRAY_BASE_OFFSET;
041  }
042
043  @Override
044  @Inline
045  public ObjectReference copy(ObjectReference from, int allocator) {
046    TIB tib = org.jikesrvm.objectmodel.ObjectModel.getTIB(from);
047    RVMType type = Magic.objectAsType(tib.getType());
048
049    if (type.isClassType())
050      return copyScalar(from, tib, type.asClass(), allocator);
051    else
052      return copyArray(from, tib, type.asArray(), allocator);
053  }
054
055  @Inline
056  private ObjectReference copyScalar(ObjectReference from, TIB tib, RVMClass type, int allocator) {
057    int bytes = org.jikesrvm.objectmodel.ObjectModel.bytesRequiredWhenCopied(from.toObject(), type);
058    int align = org.jikesrvm.objectmodel.ObjectModel.getAlignment(type, from.toObject());
059    int offset = org.jikesrvm.objectmodel.ObjectModel.getOffsetForAlignment(type, from);
060    CollectorContext context = VM.activePlan.collector();
061    allocator = context.copyCheckAllocator(from, bytes, align, allocator);
062    Address region = MemoryManager.allocateSpace(context, bytes, align, offset,
063                                                allocator, from);
064    Object toObj = org.jikesrvm.objectmodel.ObjectModel.moveObject(region, from.toObject(), bytes, type);
065    ObjectReference to = ObjectReference.fromObject(toObj);
066    context.postCopy(to, ObjectReference.fromObject(tib), bytes, allocator);
067    return to;
068  }
069
070  @Inline
071  private ObjectReference copyArray(ObjectReference from, TIB tib, RVMArray type, int allocator) {
072    int elements = Magic.getArrayLength(from.toObject());
073    int bytes = org.jikesrvm.objectmodel.ObjectModel.bytesRequiredWhenCopied(from.toObject(), type, elements);
074    int align = org.jikesrvm.objectmodel.ObjectModel.getAlignment(type, from.toObject());
075    int offset = org.jikesrvm.objectmodel.ObjectModel.getOffsetForAlignment(type, from);
076    CollectorContext context = VM.activePlan.collector();
077    allocator = context.copyCheckAllocator(from, bytes, align, allocator);
078    Address region = MemoryManager.allocateSpace(context, bytes, align, offset,
079                                                allocator, from);
080    Object toObj = org.jikesrvm.objectmodel.ObjectModel.moveObject(region, from.toObject(), bytes, type);
081    ObjectReference to = ObjectReference.fromObject(toObj);
082    context.postCopy(to, ObjectReference.fromObject(tib), bytes, allocator);
083    if (type == RVMType.CodeArrayType) {
084      // sync all moved code arrays to get icache and dcache in sync
085      // immediately.
086      int dataSize = bytes - org.jikesrvm.objectmodel.ObjectModel.computeHeaderSize(Magic.getObjectType(toObj));
087      org.jikesrvm.runtime.Memory.sync(to.toAddress(), dataSize);
088    }
089    return to;
090  }
091
092  /**
093   * Return the size of a given object, in bytes
094   *
095   * @param object The object whose size is being queried
096   * @return The size (in bytes) of the given object.
097   */
098  static int getObjectSize(ObjectReference object) {
099    TIB tib = org.jikesrvm.objectmodel.ObjectModel.getTIB(object);
100    RVMType type = Magic.objectAsType(tib.getType());
101
102    if (type.isClassType())
103      return org.jikesrvm.objectmodel.ObjectModel.bytesRequiredWhenCopied(object.toObject(), type.asClass());
104    else
105      return org.jikesrvm.objectmodel.ObjectModel.bytesRequiredWhenCopied(object.toObject(), type.asArray(), Magic.getArrayLength(object.toObject()));
106  }
107
108  /**
109   * @param region The start (or an address less than) the region that was reserved for this object.
110   */
111  @Override
112  @Inline
113  public Address copyTo(ObjectReference from, ObjectReference to, Address region) {
114    TIB tib = org.jikesrvm.objectmodel.ObjectModel.getTIB(from);
115    RVMType type = tib.getType();
116    int bytes;
117
118    boolean copy = (from != to);
119
120    if (copy) {
121      if (type.isClassType()) {
122        RVMClass classType = type.asClass();
123        bytes = org.jikesrvm.objectmodel.ObjectModel.bytesRequiredWhenCopied(from.toObject(), classType);
124        org.jikesrvm.objectmodel.ObjectModel.moveObject(from.toObject(), to.toObject(), bytes, classType);
125      } else {
126      RVMArray arrayType = type.asArray();
127        int elements = Magic.getArrayLength(from.toObject());
128        bytes = org.jikesrvm.objectmodel.ObjectModel.bytesRequiredWhenCopied(from.toObject(), arrayType, elements);
129        org.jikesrvm.objectmodel.ObjectModel.moveObject(from.toObject(), to.toObject(), bytes, arrayType);
130      }
131    } else {
132      bytes = getCurrentSize(to);
133    }
134
135    Address start = org.jikesrvm.objectmodel.ObjectModel.objectStartRef(to);
136    Allocator.fillAlignmentGap(region, start);
137
138    return start.plus(bytes);
139  }
140
141  @Override
142  public ObjectReference getReferenceWhenCopiedTo(ObjectReference from, Address to) {
143    return ObjectReference.fromObject(org.jikesrvm.objectmodel.ObjectModel.getReferenceWhenCopiedTo(from.toObject(), to));
144  }
145
146  @Override
147  public Address getObjectEndAddress(ObjectReference object) {
148    return org.jikesrvm.objectmodel.ObjectModel.getObjectEndAddress(object.toObject());
149  }
150
151  @Override
152  public int getSizeWhenCopied(ObjectReference object) {
153    return org.jikesrvm.objectmodel.ObjectModel.bytesRequiredWhenCopied(object.toObject());
154  }
155
156  @Override
157  public int getAlignWhenCopied(ObjectReference object) {
158    TIB tib = org.jikesrvm.objectmodel.ObjectModel.getTIB(object);
159    RVMType type = tib.getType();
160    if (type.isArrayType()) {
161      return org.jikesrvm.objectmodel.ObjectModel.getAlignment(type.asArray(), object.toObject());
162    } else {
163      return org.jikesrvm.objectmodel.ObjectModel.getAlignment(type.asClass(), object.toObject());
164    }
165  }
166
167  @Override
168  public int getAlignOffsetWhenCopied(ObjectReference object) {
169    TIB tib = org.jikesrvm.objectmodel.ObjectModel.getTIB(object);
170    RVMType type = tib.getType();
171    if (type.isArrayType()) {
172      return org.jikesrvm.objectmodel.ObjectModel.getOffsetForAlignment(type.asArray(), object);
173    } else {
174      return org.jikesrvm.objectmodel.ObjectModel.getOffsetForAlignment(type.asClass(), object);
175    }
176  }
177
178  @Override
179  public int getCurrentSize(ObjectReference object) {
180    return org.jikesrvm.objectmodel.ObjectModel.bytesUsed(object.toObject());
181  }
182
183  @Override
184  public ObjectReference getNextObject(ObjectReference object) {
185    return org.jikesrvm.objectmodel.ObjectModel.getNextObject(object);
186  }
187
188  @Override
189  public ObjectReference getObjectFromStartAddress(Address start) {
190    return org.jikesrvm.objectmodel.ObjectModel.getObjectFromStartAddress(start);
191  }
192
193  @Override
194  public byte [] getTypeDescriptor(ObjectReference ref) {
195    Atom descriptor = Magic.getObjectType(ref).getDescriptor();
196    return descriptor.toByteArray();
197  }
198
199  @Override
200  @Inline
201  public int getArrayLength(ObjectReference object) {
202    return Magic.getArrayLength(object.toObject());
203  }
204
205  @Override
206  public boolean isArray(ObjectReference object) {
207    return org.jikesrvm.objectmodel.ObjectModel.getObjectType(object.toObject()).isArrayType();
208  }
209
210  @Override
211  public boolean isPrimitiveArray(ObjectReference object) {
212    Object obj = object.toObject();
213    return (obj instanceof long[]   ||
214            obj instanceof int[]    ||
215            obj instanceof short[]  ||
216            obj instanceof byte[]   ||
217            obj instanceof double[] ||
218            obj instanceof float[]);
219  }
220
221  /**
222   * Tests a bit available for memory manager use in an object.
223   *
224   * @param object the address of the object
225   * @param idx the index of the bit
226   * @return {@code true} if argument bit is 1, {@code false} if it is 0
227   */
228  public boolean testAvailableBit(ObjectReference object, int idx) {
229    return org.jikesrvm.objectmodel.ObjectModel.testAvailableBit(object.toObject(), idx);
230  }
231
232  /**
233   * Sets a bit available for memory manager use in an object.
234   *
235   * @param object the address of the object
236   * @param idx the index of the bit
237   * @param flag <code>true</code> to set the bit to 1,
238   * <code>false</code> to set it to 0
239   */
240  public void setAvailableBit(ObjectReference object, int idx,
241                                     boolean flag) {
242    org.jikesrvm.objectmodel.ObjectModel.setAvailableBit(object.toObject(), idx, flag);
243  }
244
245  @Override
246  public boolean attemptAvailableBits(ObjectReference object,
247                                             Word oldVal, Word newVal) {
248    return org.jikesrvm.objectmodel.ObjectModel.attemptAvailableBits(object.toObject(), oldVal,
249                                               newVal);
250  }
251
252  @Override
253  public Word prepareAvailableBits(ObjectReference object) {
254    return org.jikesrvm.objectmodel.ObjectModel.prepareAvailableBits(object.toObject());
255  }
256
257  @Override
258  public void writeAvailableByte(ObjectReference object, byte val) {
259    org.jikesrvm.objectmodel.ObjectModel.writeAvailableByte(object.toObject(), val);
260  }
261
262  @Override
263  public byte readAvailableByte(ObjectReference object) {
264    return org.jikesrvm.objectmodel.ObjectModel.readAvailableByte(object.toObject());
265  }
266
267  @Override
268  public void writeAvailableBitsWord(ObjectReference object, Word val) {
269    org.jikesrvm.objectmodel.ObjectModel.writeAvailableBitsWord(object.toObject(), val);
270  }
271
272  @Override
273  public Word readAvailableBitsWord(ObjectReference object) {
274    return org.jikesrvm.objectmodel.ObjectModel.readAvailableBitsWord(object.toObject());
275  }
276
277  /* AJG: Should this be a variable rather than method? */
278  @Override
279  public Offset GC_HEADER_OFFSET() {
280    return GC_HEADER_OFFSET;
281  }
282
283  @Override
284  @Inline
285  public Address objectStartRef(ObjectReference object) {
286    return org.jikesrvm.objectmodel.ObjectModel.objectStartRef(object);
287  }
288
289  @Override
290  public Address refToAddress(ObjectReference object) {
291    return org.jikesrvm.objectmodel.ObjectModel.getPointerInMemoryRegion(object);
292  }
293
294  @Override
295  @Inline
296  public boolean isAcyclic(ObjectReference typeRef) {
297    TIB tib = Magic.addressAsTIB(typeRef.toAddress());
298    RVMType type = tib.getType();
299    return type.isAcyclicReference();
300  }
301
302  @Override
303  public void dumpObject(ObjectReference object) {
304    DebugUtil.dumpRef(object);
305  }
306}
307