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