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