001/*
002 * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.
008 *
009 * This code is distributed in the hope that it will be useful, but WITHOUT
010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
011 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
012 * version 2 for more details (a copy is included in the LICENSE file that
013 * accompanied this code).
014 *
015 * You should have received a copy of the GNU General Public License version
016 * 2 along with this work; if not, write to the Free Software Foundation,
017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
018 *
019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
020 * or visit www.oracle.com if you need additional information or have any
021 * questions.
022 */
023package jdk.internal.jvmci.code;
024
025import java.util.*;
026
027import jdk.internal.jvmci.meta.*;
028
029/**
030 * The callee save area (CSA) is a contiguous space in a stack frame used to save (and restore) the
031 * values of the caller's registers. This class describes the layout of a CSA in terms of its
032 * {@linkplain #size size}, {@linkplain #slotSize slot size} and the {@linkplain #registers callee
033 * save registers} covered by the CSA.
034 */
035public class CalleeSaveLayout {
036
037    /**
038     * The size (in bytes) of the CSA.
039     */
040    public final int size;
041
042    /**
043     * The size (in bytes) of an {@linkplain #registerAt(int) indexable} slot in the CSA.
044     */
045    public final int slotSize;
046
047    /**
048     * Map from {@linkplain Register#number register numbers} to slot indexes in the CSA.
049     */
050    private final int[] regNumToIndex;
051
052    private final Register[] indexToReg;
053
054    /**
055     * The list of registers {@linkplain #contains(int) contained} by this CSA.
056     */
057    public final Register[] registers;
058
059    /**
060     * The offset from the frame pointer to the CSA. If this is not known, then this field will have
061     * the value {@link Integer#MAX_VALUE}.
062     */
063    public final int frameOffsetToCSA;
064
065    /**
066     * Creates a CSA layout.
067     *
068     * @param size size (in bytes) of the CSA. If this is {@code -1}, then the CSA size will be
069     *            computed from {@code registers}.
070     * @param slotSize the size (in bytes) of an {@linkplain #registerAt(int) indexable} slot in the
071     *            CSA
072     * @param registers the registers that can be saved in the CSA
073     */
074    public CalleeSaveLayout(TargetDescription target, int frameOffsetToCSA, int size, int slotSize, Register... registers) {
075        this.frameOffsetToCSA = frameOffsetToCSA;
076        assert slotSize == 0 || CodeUtil.isPowerOf2(slotSize);
077        this.slotSize = slotSize;
078        int maxRegNum = -1;
079        int maxOffset = 0;
080        this.registers = registers;
081        int offset = 0;
082        for (Register reg : registers) {
083            assert offset % slotSize == 0;
084            assert reg.number >= 0;
085            if (reg.number > maxRegNum) {
086                maxRegNum = reg.number;
087            }
088            if (offset > maxOffset) {
089                maxOffset = offset;
090            }
091            PlatformKind kind = target.arch.getLargestStorableKind(reg.getRegisterCategory());
092            offset += target.getSizeInBytes(kind);
093        }
094        if (size == -1) {
095            this.size = offset;
096        } else {
097            assert offset <= size;
098            this.size = size;
099        }
100
101        this.regNumToIndex = new int[maxRegNum + 1];
102        this.indexToReg = offset == 0 ? new Register[0] : new Register[offset / slotSize];
103        Arrays.fill(regNumToIndex, -1);
104        offset = 0;
105        for (Register reg : registers) {
106            int index = offset / slotSize;
107            regNumToIndex[reg.number] = index;
108            indexToReg[index] = reg;
109            PlatformKind kind = target.arch.getLargestStorableKind(reg.getRegisterCategory());
110            offset += target.getSizeInBytes(kind);
111        }
112    }
113
114    /**
115     * Gets the offset of a given register in the CSA.
116     *
117     * @return the offset (in bytes) of {@code reg} in the CSA
118     * @throws IllegalArgumentException if {@code reg} does not have a slot in the CSA
119     */
120    public int offsetOf(int reg) {
121        return indexOf(reg) * slotSize;
122    }
123
124    /**
125     * Gets the index of a given register in the CSA.
126     *
127     * @return the index of {@code reg} in the CSA
128     * @throws IllegalArgumentException if {@code reg} does not have a slot in the CSA
129     */
130    public int indexOf(int reg) {
131        if (!contains(reg)) {
132            throw new IllegalArgumentException(String.valueOf(reg));
133        }
134        return regNumToIndex[reg];
135    }
136
137    /**
138     * Gets the offset of a given register in the CSA.
139     *
140     * @return the offset (in bytes) of {@code reg} in the CSA
141     * @throws IllegalArgumentException if {@code reg} does not have a slot in the CSA
142     */
143    public int offsetOf(Register reg) {
144        return offsetOf(reg.number);
145    }
146
147    /**
148     * Determines if the CSA includes a slot for a given register.
149     *
150     * @param reg the register to test
151     * @return true if the CSA contains a slot for {@code reg}
152     */
153    public boolean contains(int reg) {
154        return reg >= 0 && reg < regNumToIndex.length && regNumToIndex[reg] != -1;
155    }
156
157    /**
158     * Gets the register whose slot in the CSA is at a given index.
159     *
160     * @param index an index of a slot in the CSA
161     * @return the register whose slot in the CSA is at {@code index} or {@code null} if
162     *         {@code index} does not denote a slot in the CSA aligned with a register
163     */
164    public Register registerAt(int index) {
165        if (index < 0 || index >= indexToReg.length) {
166            return null;
167        }
168        return indexToReg[index];
169    }
170
171    @Override
172    public String toString() {
173        StringBuilder sb = new StringBuilder("[");
174        for (Register reg : registers) {
175            if (sb.length() != 1) {
176                sb.append(", ");
177            }
178            sb.append(reg).append("{+").append(offsetOf(reg)).append('}');
179        }
180        return sb.append("] size=").append(size).toString();
181    }
182}