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 }