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.objectmodel;
014
015import static org.jikesrvm.runtime.JavaSizeConstants.LOG_BYTES_IN_LONG;
016
017import org.jikesrvm.VM;
018import org.jikesrvm.classloader.RVMClass;
019import org.jikesrvm.runtime.Memory;
020
021/**
022 * Layout fields in an object, packed like sardines in a crushed tin box.
023 */
024public class FieldLayoutPacked extends FieldLayout {
025
026  /**
027   * Lay out an object, maintaining offsets of free slots of size 1,2,4 and 8
028   * bytes.
029   */
030  private static class LayoutContext extends FieldLayoutContext {
031    private static final int LOG_MAX_SLOT_SIZE = LOG_BYTES_IN_LONG;
032    private static final int MAX_SLOT_SIZE = (1 << LOG_MAX_SLOT_SIZE);
033
034    private short slot0;
035    private short slot1;
036    private short slot2;
037
038    private short get(int logSize) {
039      switch (logSize) {
040        case 0: return slot0;
041        case 1: return slot1;
042        case 2: return slot2;
043        case 3: return (short)Memory.alignUp(getObjectSize(), MAX_SLOT_SIZE);
044        default: VM.sysFail("Invalid slot"); return -1;
045      }
046    }
047
048    private void set(int logSize, int value) {
049      if (VM.VerifyAssertions) VM._assert(value >= 0 && value < Short.MAX_VALUE);
050      short shortValue = (short)value;
051      switch (logSize) {
052        case 0: slot0 = shortValue; break;
053        case 1: slot1 = shortValue; break;
054        case 2: slot2 = shortValue; break;
055        case 3: if (VM.VerifyAssertions) VM._assert(shortValue == 0);
056      }
057    }
058
059    /**
060     * Create a layout for an object, initializing offsets from its
061     * superclass.
062     *
063     * @param alignment Current alignment of first field.
064     * @param superLayout Superclass layout context
065     */
066    LayoutContext(byte alignment, LayoutContext superLayout) {
067      super(alignment, superLayout);
068      if (superLayout != null) {
069        for (int i = 0; i < LOG_MAX_SLOT_SIZE; i++) {
070          set(i, superLayout.get(i));
071        }
072      }
073    }
074
075    /**
076     * Return the next available offset for a given size
077     *
078     * @param size Size of the field to be laid out.  Must be
079     * a power of 2.
080     */
081    @Override
082    int nextOffset(int size, boolean isReference) {
083      if (VM.VerifyAssertions) VM._assert((size & (size - 1)) == 0);  // Ensure =2^n
084      adjustAlignment(size);
085
086      /* Calculate the log of the size of the field */
087      int logSize = log2(size);
088      int result = 0;
089
090      /* Find a free slot */
091      for (int i = logSize; i <= LOG_MAX_SLOT_SIZE; i++) {
092        int slot = get(i);
093        if (slot != 0 || i == LOG_MAX_SLOT_SIZE) {
094          result = slot;
095          set(i, 0);
096          /* Set any holes we have created */
097          for (i = i - 1; i >= logSize; i--) {
098            if (VM.VerifyAssertions) VM._assert(get(i) == 0);
099            set(i, result + (1 << i));
100          }
101          break;
102        }
103      }
104
105      /* Make sure the field fits */
106      ensureObjectSize(result + size);
107
108      if (DEBUG) {
109        VM.sysWrite("  field: & offset ", result, " New object size = ", getObjectSize());
110        VM.sysWrite(" slots: ");
111        for (int i = 0; i < LOG_MAX_SLOT_SIZE; i++) {
112          VM.sysWrite(get(i), i == LOG_MAX_SLOT_SIZE - 1 ? "" : ", ");
113        }
114        VM.sysWriteln();
115      }
116
117      /* Bounds check - scalar objects this size are impossible, surely ?? */
118      if (result >= Short.MAX_VALUE) {
119        VM.sysFail("Scalar class size exceeds offset width");
120      }
121
122      return result;
123    }
124  }
125
126  public FieldLayoutPacked(boolean largeFieldsFirst, boolean clusterReferenceFields) {
127    super(largeFieldsFirst, clusterReferenceFields);
128  }
129
130  /**
131   * @param klass the class to layout
132   * @return The layout context
133   * @see FieldLayout#getLayoutContext(RVMClass)
134   */
135  @Override
136  protected FieldLayoutContext getLayoutContext(RVMClass klass) {
137    return new LayoutContext((byte) klass.getAlignment(), (LayoutContext) klass.getFieldLayoutContext());
138  }
139}