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.classloader.RVMField;
019 import org.vmmagic.unboxed.Offset;
020
021 /**
022 * This abstract class defines the interface for schemes that layout fields
023 * in an object. Not header fields, (scalar) object fields.
024 *
025 * The field layout object encapsulates layout state.
026 */
027 public abstract class FieldLayout implements SizeConstants {
028
029 /**
030 * Enable debugging
031 */
032 protected static final boolean DEBUG = false;
033
034 /** Whether to lay out 8byte values first in order to avoid some holes */
035 private final boolean largeFieldsFirst;
036
037 /** Lay out reference fields in a block */
038 private final boolean clusterReferenceFields;
039
040 public FieldLayout(boolean largeFieldsFirst, boolean clusterReferenceFields) {
041 this.largeFieldsFirst = largeFieldsFirst;
042 this.clusterReferenceFields = clusterReferenceFields;
043 }
044
045 /**
046 * Maximum of two integers
047 */
048 protected static int max(int x, int y) {
049 return (x > y) ? x : y;
050 }
051
052 /**
053 * Log base 2 of an integer
054 */
055 protected static int log2(int x) {
056 int logSize = 0;
057 while ((1 << logSize) < x) {
058 logSize += 1;
059 }
060 return logSize;
061 }
062
063 /*
064 * Abstract methods that determine the behaviour of a particular layout scheme
065 */
066
067 /**
068 * Return the appropriate layout context object for the given class.
069 *
070 * @param klass The class
071 * @return The layout context
072 */
073 protected abstract FieldLayoutContext getLayoutContext(RVMClass klass);
074
075 /**
076 * This is where a class gets laid out. Differences in layout strategy
077 * are largely encapsulated in the layoutContext object.
078 *
079 * @param klass The class to lay out.
080 */
081 public void layoutInstanceFields(RVMClass klass) {
082 /*
083 * Determine available field slots from parent classes, and allocate
084 * a new context object for this class and its children.
085 */
086 FieldLayoutContext fieldLayout = getLayoutContext(klass);
087
088 // Preferred alignment of object - modified to reflect added fields
089 // New fields to be allocated for this object
090 RVMField[] fields = klass.getDeclaredFields();
091
092 if (DEBUG) {
093 VM.sysWriteln("Laying out: ", klass.toString());
094 }
095
096 /*
097 * Layout reference fields first pre-pass - This can help some
098 * GC schemes.
099 */
100 if (clusterReferenceFields) {
101 // For every field
102 for (RVMField field : fields) {
103 if (!field.isStatic() && !field.hasOffset()) {
104 if (field.isReferenceType()) {
105 layoutField(fieldLayout, klass, field, BYTES_IN_ADDRESS);
106 }
107 }
108 }
109 }
110
111 /*
112 * Layout 8byte values first pre-pass - do this to avoid unnecessary
113 * holes for object layouts such as an int followed by a long
114 */
115 if (largeFieldsFirst) {
116 // For every field
117 for (RVMField field : fields) {
118 // Should we allocate space in the object now?
119 if (!field.isStatic() && !field.hasOffset()) {
120 if (field.getSize() == BYTES_IN_LONG) {
121 layoutField(fieldLayout, klass, field, BYTES_IN_LONG);
122 }
123 }
124 }
125 }
126
127 for (RVMField field : fields) { // For every field
128 int fieldSize = field.getSize(); // size of field
129 if (!field.isStatic() && !field.hasOffset()) { // Allocate space in the object?
130 layoutField(fieldLayout, klass, field, fieldSize);
131 }
132 }
133 // JavaHeader requires objects to be int sized/aligned
134 if (VM.VerifyAssertions) VM._assert((fieldLayout.getObjectSize() & 0x3) == 0);
135
136 /* Update class to reflect changes */
137
138 updateClass(klass, fieldLayout);
139 }
140
141 /**
142 * Update the RVMClass with context info.
143 *
144 * @param klass
145 * @param fieldLayout
146 */
147 protected void updateClass(RVMClass klass, FieldLayoutContext fieldLayout) {
148 /*
149 * Save the new field layout.
150 */
151 klass.setFieldLayoutContext(fieldLayout);
152
153 klass.setInstanceSizeInternal(ObjectModel.computeScalarHeaderSize(klass) + fieldLayout.getObjectSize());
154 klass.setAlignment(fieldLayout.getAlignment());
155 }
156
157 /**
158 * Update a field to set its offset within the object.
159 *
160 * @param klass
161 * @param field
162 * @param offset
163 */
164 protected void setOffset(RVMClass klass, RVMField field, int offset) {
165
166 Offset fieldOffset;
167 if (offset >= 0) {
168 fieldOffset =
169 Offset.fromIntSignExtend(JavaHeader.objectStartOffset(klass) +
170 ObjectModel.computeScalarHeaderSize(klass) +
171 offset);
172 } else {
173 /* Negative offsets go before the header */
174 fieldOffset = Offset.fromIntSignExtend(JavaHeader.objectStartOffset(klass) + offset);
175 }
176 field.setOffset(fieldOffset);
177 if (DEBUG) {
178 VM.sysWrite(" field: ", field.toString());
179 VM.sysWriteln(" offset ", fieldOffset.toInt());
180 }
181 }
182
183 /**
184 * Lay out a given field.
185 *
186 * @param layout State for the layout process
187 * @param klass The class whose fields we're laying out.
188 * @param field The field we are laying out.
189 * @param fieldSize The size of the field.
190 */
191 protected void layoutField(FieldLayoutContext layout, RVMClass klass, RVMField field, int fieldSize) {
192 boolean isRef = field.isReferenceType();
193 setOffset(klass, field, layout.nextOffset(fieldSize, isRef));
194 }
195 }