/*
* This file is part of the Jikes RVM project (http://jikesrvm.org).
*
* This file is licensed to You under the Eclipse Public License (EPL);
* You may not use this file except in compliance with the License. You
* may obtain a copy of the License at
*
* http://www.opensource.org/licenses/eclipse-1.0.php
*
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership.
*/
package org.jikesrvm.objectmodel;
import static org.jikesrvm.runtime.JavaSizeConstants.LOG_BYTES_IN_LONG;
import org.jikesrvm.VM;
import org.jikesrvm.classloader.RVMClass;
import org.jikesrvm.runtime.Memory;
/**
* Layout fields in an object, packed like sardines in a crushed tin box.
*/
public class FieldLayoutPacked extends FieldLayout {
/**
* Lay out an object, maintaining offsets of free slots of size 1,2,4 and 8
* bytes.
*/
private static class LayoutContext extends FieldLayoutContext {
private static final int LOG_MAX_SLOT_SIZE = LOG_BYTES_IN_LONG;
private static final int MAX_SLOT_SIZE = (1 << LOG_MAX_SLOT_SIZE);
private short slot0;
private short slot1;
private short slot2;
private short get(int logSize) {
switch (logSize) {
case 0: return slot0;
case 1: return slot1;
case 2: return slot2;
case 3: return (short)Memory.alignUp(getObjectSize(), MAX_SLOT_SIZE);
default:
VM.sysFail("Invalid slot");
return -1;
}
}
private void set(int logSize, int value) {
if (VM.VerifyAssertions) VM._assert(value >= 0 && value < Short.MAX_VALUE);
short shortValue = (short)value;
switch (logSize) {
case 0: slot0 = shortValue; break;
case 1: slot1 = shortValue; break;
case 2: slot2 = shortValue; break;
case 3: if (VM.VerifyAssertions) VM._assert(shortValue == 0);
}
}
/**
* Create a layout for an object, initializing offsets from its
* superclass.
*
* @param alignment Current alignment of first field.
* @param superLayout Superclass layout context
*/
LayoutContext(byte alignment, LayoutContext superLayout) {
super(alignment, superLayout);
if (superLayout != null) {
for (int i = 0; i < LOG_MAX_SLOT_SIZE; i++) {
set(i, superLayout.get(i));
}
}
}
/**
* Return the next available offset for a given size
*
* @param size Size of the field to be laid out. Must be
* a power of 2.
*/
@Override
int nextOffset(int size, boolean isReference) {
if (VM.VerifyAssertions) VM._assert((size & (size - 1)) == 0); // Ensure =2^n
adjustAlignment(size);
/* Calculate the log of the size of the field */
int logSize = log2(size);
int result = 0;
/* Find a free slot */
for (int i = logSize; i <= LOG_MAX_SLOT_SIZE; i++) {
int slot = get(i);
if (slot != 0 || i == LOG_MAX_SLOT_SIZE) {
result = slot;
set(i, 0);
/* Set any holes we have created */
for (i = i - 1; i >= logSize; i--) {
if (VM.VerifyAssertions) VM._assert(get(i) == 0);
set(i, result + (1 << i));
}
break;
}
}
/* Make sure the field fits */
ensureObjectSize(result + size);
if (DEBUG) {
VM.sysWrite(" field: & offset ", result, " New object size = ", getObjectSize());
VM.sysWrite(" slots: ");
for (int i = 0; i < LOG_MAX_SLOT_SIZE; i++) {
VM.sysWrite(get(i), i == LOG_MAX_SLOT_SIZE - 1 ? "" : ", ");
}
VM.sysWriteln();
}
/* Bounds check - scalar objects this size are impossible, surely ?? */
if (result >= Short.MAX_VALUE) {
VM.sysFail("Scalar class size exceeds offset width");
}
return result;
}
}
public FieldLayoutPacked(boolean largeFieldsFirst, boolean clusterReferenceFields) {
super(largeFieldsFirst, clusterReferenceFields);
}
/**
* @param klass the class to layout
* @return The layout context
* @see FieldLayout#getLayoutContext(RVMClass)
*/
@Override
protected FieldLayoutContext getLayoutContext(RVMClass klass) {
return new LayoutContext((byte) klass.getAlignment(), (LayoutContext) klass.getFieldLayoutContext());
}
}