/* * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.max.vm.compiler.target; import static com.sun.max.vm.VMConfiguration.*; import static com.sun.max.vm.compiler.target.TargetBundleLayout.ArrayField.*; import java.util.*; import com.sun.max.lang.*; import com.sun.max.unsafe.*; import com.sun.max.vm.*; import com.sun.max.vm.heap.*; import com.sun.max.vm.layout.*; import com.sun.max.vm.type.*; /** * Describes the layout of a contiguous chunk of memory in a code region that contains * the arrays referenced by some {@linkplain ArrayField array fields} in a {@link TargetMethod}. * These arrays contain the machine code and data that must be co-located. */ public final class TargetBundleLayout { /** * Constants denoting the arrays referenced by fields in {@link TargetMethod} that are colocated in a target bundle. */ public enum ArrayField { scalarLiterals(false), referenceLiterals(false), code(true); public static final List<ArrayField> VALUES = Arrays.asList(values()); public final ArrayLayout arrayLayout; ArrayField(boolean allocateEmptyArray) { final LayoutScheme layoutScheme = vmConfig().layoutScheme(); final String fieldName = name(); final TypeDescriptor fieldType = JavaTypeDescriptor.forJavaClass(Classes.getDeclaredField(TargetMethod.class, fieldName).getType()); assert JavaTypeDescriptor.isArray(fieldType); arrayLayout = fieldType.componentTypeDescriptor().toKind().arrayLayout(layoutScheme); this.allocateEmptyArray = allocateEmptyArray; } /** * Determines if space should be reserved for the array referenced by this field if the length of the array is 0. */ public final boolean allocateEmptyArray; /** * Allocates space within a target bundle for a cell of a given size. If {@code size.isZero() == true}, no space is * allocated. * * @param region an object used to do the allocation * @param size the size of the cell to allocate * @return the offset from the start of the target bundle of the allocate cell. If {@code size.isZero()}, then * no space is allocated and {@link TargetBundleLayout#INVALID_OFFSET} is returned. */ private Offset allocate(LinearAllocatorRegion region, Size size) { if (size.isZero()) { return INVALID_OFFSET; } final Pointer cell = region.allocate(size, true); assert !cell.isZero() || !region.getAllocationMark().isZero(); return cell.asOffset(); } /** * Updates the cell allocated for the array referenced by this field. If {@code length == 0} and this field does * not {@linkplain #allocateEmptyArray allocate} space for empty arrays, no space is allocated. * * @param length the length of the array for which space should be allocated * @param targetBundleLayout the target bundle layout recording the field cell allocations * @param region an object used to do the allocation */ void update(int length, TargetBundleLayout targetBundleLayout, LinearAllocatorRegion region) { final int ordinal = ordinal(); targetBundleLayout.lengths[ordinal] = length; final Size cellSize; if (allocateEmptyArray || length != 0) { cellSize = arrayLayout.getArraySize(length); } else { cellSize = Size.zero(); } WordArray.set(targetBundleLayout.cellSizes, ordinal, cellSize); WordArray.set(targetBundleLayout.cellOffsets, ordinal, allocate(region, cellSize)); } } /** * Constant denoting an invalid offset in a target bundle. */ public static final Offset INVALID_OFFSET = Offset.fromLong(-1); final int[] lengths; final Size[] cellSizes; final Offset[] cellOffsets; private Size bundleSize; public TargetBundleLayout(int numberOfScalarLiteralBytes, int numberOfReferenceLiterals, int numberOfCodeBytes) { final LinearAllocatorRegion region = new LinearAllocatorRegion(Address.zero(), Size.fromLong(Long.MAX_VALUE), "TargetBundle"); final int numberOfFields = ArrayField.VALUES.size(); lengths = new int[numberOfFields]; cellSizes = new Size[numberOfFields]; cellOffsets = new Offset[numberOfFields]; WordArray.fill(cellOffsets, INVALID_OFFSET); if (MaxineVM.isHosted()) { bundleSize = Size.zero(); } initialize(scalarLiterals, numberOfScalarLiteralBytes, region); initialize(referenceLiterals, numberOfReferenceLiterals, region); initialize(code, numberOfCodeBytes, region); bundleSize = region.getAllocationMark().asSize(); assert bundleSize.isWordAligned(); } /** * Gets the size of the cell allocated in this target bundle for the array referenced by a given field. * * @param field the field for which the cell size is being requested * @return the size of the cell allocated for the array referenced by {@code field} (which may be * {@link Size#zero()}) */ public Size cellSize(ArrayField field) { return WordArray.get(cellSizes, field.ordinal()).asSize(); } /** * Gets the offset relative to the start of this bundle of the cell reserved for the array referenced by a given * field. * * @param field the field for which the cell offset is being requested * @return the offset relative to the start of this bundle of the cell reserved for {@code field} * @throws IllegalArgumentException if no cell has been allocated for {@code field} in this target bundle */ public Offset cellOffset(ArrayField field) throws IllegalArgumentException { final Offset cellOffset = WordArray.get(cellOffsets, field.ordinal()).asOffset(); if (cellOffset.equals(INVALID_OFFSET)) { assert cellSize(field).isZero(); throw new IllegalArgumentException(); } assert !cellSize(field).isZero(); return cellOffset; } /** * Gets the offset relative to the start of this bundle of the end of the cell reserved for the array referenced by * a given field. * * @param field the field for which the cell end offset is being requested * @return the offset relative to the start of this bundle of the end of the cell reserved for {@code field} * @throws IllegalArgumentException if no cell has been allocated for {@code field} in this target bundle */ public Offset cellEndOffset(ArrayField field) throws IllegalArgumentException { return cellOffset(field).plus(cellSize(field)); } /** * Gets the offset relative to the start of this bundle of the first element in the cell reserved for the array * referenced by a given field. * * @param field the field for which the cell offset is being requested * @return the offset relative to the start of this bundle of the first element of {@code field} * @throws IllegalArgumentException if no cell has been allocated for {@code field} in this target bundle */ public Offset firstElementOffset(ArrayField field) throws IllegalArgumentException { return cellOffset(field).plus(field.arrayLayout.getElementOffsetInCell(0)); } /** * Gets the address of the cell containing the array in this target bundle referenced by a given field. * * @param start the start address of the target bundle * @param field the field for which the cell address is being requested * @return the address of the cell containing the array referenced {@code field} * @throws IllegalArgumentException if no cell has been allocated for {@code field} in this target bundle */ public Pointer cell(Address start, ArrayField field) { return start.plus(cellOffset(field)).asPointer(); } /** * Gets the address of the end of the cell containing the array in this target bundle referenced by a given field. * * @param start the start address of the target bundle * @param field the field for which the cell end address is being requested * @return the address of the end of the cell containing the array referenced {@code field} * @throws IllegalArgumentException if no cell has been allocated for {@code field} in this target bundle */ public Pointer cellEnd(Address start, ArrayField field) { return start.plus(cellEndOffset(field)).asPointer(); } /** * Gets the address of the first element in the array in this target bundle referenced by a given field. * * @param start the start address of the target bundle * @param field the field for which the first element address is being requested * @return the address of the first element of the array referenced by {@code field} * @throws IllegalArgumentException if no cell has been allocated for {@code field} in this target bundle */ public Pointer firstElementPointer(Address start, ArrayField field) { return start.plus(firstElementOffset(field)).asPointer(); } /** * Gets the array length based on which size of the cell reserved for a given field was calculated. * @param field the array field * @return the length */ public int length(ArrayField field) { return lengths[field.ordinal()]; } /** * Gets the total size of this target bundle. * * @return the size of the entire bundle */ public Size bundleSize() { return bundleSize; } private void initialize(ArrayField field, int length, LinearAllocatorRegion region) { field.update(length, this, region); } @Override public String toString() { final StringBuilder sb = new StringBuilder(); for (ArrayField field : VALUES) { final Size cellSize = cellSize(field); if (!cellSize.isZero()) { final Offset cellOffset = cellOffset(field); sb.append(String.format("%-20s [%3d - %-3d) data@%-4d length=%-3d size=%-3d type=%s%n", field.name() + ":", cellOffset.toInt(), cellEndOffset(field).toInt(), firstElementOffset(field).toInt(), length(field), cellSize.toInt(), field.arrayLayout.elementKind() + "[]")); } } sb.append("bundle size=").append(bundleSize().toInt()); return sb.toString(); } /** * Creates an object describing the layout of the target bundle associated with a given target method. */ public static TargetBundleLayout from(TargetMethod targetMethod) { return new TargetBundleLayout(targetMethod.numberOfScalarLiteralBytes(), targetMethod.numberOfReferenceLiterals(), targetMethod.codeLength()); } }