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 * <p> 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 }