001/*
002 * Copyright (c) 2009, 2015, 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 com.oracle.graal.lir.framemap;
024
025import java.util.*;
026
027import jdk.internal.jvmci.code.*;
028import jdk.internal.jvmci.meta.*;
029
030import com.oracle.graal.asm.*;
031
032/**
033 * This class is used to build the stack frame layout for a compiled method. A {@link StackSlot} is
034 * used to index slots of the frame relative to the stack pointer. The frame size is only fixed
035 * after register allocation when all spill slots have been allocated. Both the outgoing argument
036 * area and the spill are can grow until then. Therefore, outgoing arguments are indexed from the
037 * stack pointer, while spill slots are indexed from the beginning of the frame (and the total frame
038 * size has to be added to get the actual offset from the stack pointer).
039 */
040public abstract class FrameMap {
041
042    private final TargetDescription target;
043    private final RegisterConfig registerConfig;
044
045    public interface ReferenceMapBuilderFactory {
046
047        ReferenceMapBuilder newReferenceMapBuilder(int totalFrameSize);
048    }
049
050    private final ReferenceMapBuilderFactory referenceMapFactory;
051
052    /**
053     * The final frame size, not including the size of the
054     * {@link Architecture#getReturnAddressSize() return address slot}. The value is only set after
055     * register allocation is complete, i.e., after all spill slots have been allocated.
056     */
057    private int frameSize;
058
059    /**
060     * Initial size of the area occupied by spill slots and other stack-allocated memory blocks.
061     */
062    protected int initialSpillSize;
063
064    /**
065     * Size of the area occupied by spill slots and other stack-allocated memory blocks.
066     */
067    protected int spillSize;
068
069    /**
070     * Size of the area occupied by outgoing overflow arguments. This value is adjusted as calling
071     * conventions for outgoing calls are retrieved. On some platforms, there is a minimum outgoing
072     * size even if no overflow arguments are on the stack.
073     */
074    protected int outgoingSize;
075
076    /**
077     * Determines if this frame has values on the stack for outgoing calls.
078     */
079    private boolean hasOutgoingStackArguments;
080
081    /**
082     * The list of stack slots allocated in this frame that are present in every reference map.
083     */
084    private final List<StackSlot> objectStackSlots;
085
086    /**
087     * Records whether an offset to an incoming stack argument was ever returned by
088     * {@link #offsetForStackSlot(StackSlot)}.
089     */
090    private boolean accessesCallerFrame;
091
092    /**
093     * Creates a new frame map for the specified method. The given registerConfig is optional, in
094     * case null is passed the default RegisterConfig from the CodeCacheProvider will be used.
095     */
096    public FrameMap(CodeCacheProvider codeCache, RegisterConfig registerConfig, ReferenceMapBuilderFactory referenceMapFactory) {
097        this.target = codeCache.getTarget();
098        this.registerConfig = registerConfig == null ? codeCache.getRegisterConfig() : registerConfig;
099        this.frameSize = -1;
100        this.outgoingSize = codeCache.getMinimumOutgoingSize();
101        this.objectStackSlots = new ArrayList<>();
102        this.referenceMapFactory = referenceMapFactory;
103    }
104
105    public RegisterConfig getRegisterConfig() {
106        return registerConfig;
107    }
108
109    public TargetDescription getTarget() {
110        return target;
111    }
112
113    public void addLiveValues(ReferenceMapBuilder refMap) {
114        for (Value value : objectStackSlots) {
115            refMap.addLiveValue(value);
116        }
117    }
118
119    protected int returnAddressSize() {
120        return getTarget().arch.getReturnAddressSize();
121    }
122
123    protected int calleeSaveAreaSize() {
124        CalleeSaveLayout csl = getRegisterConfig().getCalleeSaveLayout();
125        return csl != null ? csl.size : 0;
126    }
127
128    /**
129     * Determines if an offset to an incoming stack argument was ever returned by
130     * {@link #offsetForStackSlot(StackSlot)}.
131     */
132    public boolean accessesCallerFrame() {
133        return accessesCallerFrame;
134    }
135
136    /**
137     * Gets the frame size of the compiled frame, not including the size of the
138     * {@link Architecture#getReturnAddressSize() return address slot}.
139     *
140     * @return The size of the frame (in bytes).
141     */
142    public int frameSize() {
143        assert frameSize != -1 : "frame size not computed yet";
144        return frameSize;
145    }
146
147    public int outgoingSize() {
148        return outgoingSize;
149    }
150
151    /**
152     * Determines if any space is used in the frame apart from the
153     * {@link Architecture#getReturnAddressSize() return address slot}.
154     */
155    public boolean frameNeedsAllocating() {
156        int unalignedFrameSize = spillSize - returnAddressSize();
157        return hasOutgoingStackArguments || unalignedFrameSize != 0;
158    }
159
160    /**
161     * Gets the total frame size of the compiled frame, including the size of the
162     * {@link Architecture#getReturnAddressSize() return address slot}.
163     *
164     * @return The total size of the frame (in bytes).
165     */
166    public abstract int totalFrameSize();
167
168    /**
169     * Gets the current size of this frame. This is the size that would be returned by
170     * {@link #frameSize()} if {@link #finish()} were called now.
171     */
172    public abstract int currentFrameSize();
173
174    /**
175     * Aligns the given frame size to the stack alignment size and return the aligned size.
176     *
177     * @param size the initial frame size to be aligned
178     * @return the aligned frame size
179     */
180    protected abstract int alignFrameSize(int size);
181
182    /**
183     * Computes the final size of this frame. After this method has been called, methods that change
184     * the frame size cannot be called anymore, e.g., no more spill slots or outgoing arguments can
185     * be requested.
186     */
187    public void finish() {
188        frameSize = currentFrameSize();
189        if (frameSize > getRegisterConfig().getMaximumFrameSize()) {
190            throw new BailoutException("Frame size (%d) exceeded maximum allowed frame size (%d).", frameSize, getRegisterConfig().getMaximumFrameSize());
191        }
192    }
193
194    /**
195     * Computes the offset of a stack slot relative to the frame register.
196     *
197     * @param slot a stack slot
198     * @return the offset of the stack slot
199     */
200    public int offsetForStackSlot(StackSlot slot) {
201        if (slot.isInCallerFrame()) {
202            accessesCallerFrame = true;
203        }
204        return slot.getOffset(totalFrameSize());
205    }
206
207    /**
208     * Gets the offset from the stack pointer to the stack area where callee-saved registers are
209     * stored.
210     *
211     * @return The offset to the callee save area (in bytes).
212     */
213    public abstract int offsetToCalleeSaveArea();
214
215    /**
216     * Informs the frame map that the compiled code calls a particular method, which may need stack
217     * space for outgoing arguments.
218     *
219     * @param cc The calling convention for the called method.
220     */
221    public void callsMethod(CallingConvention cc) {
222        reserveOutgoing(cc.getStackSize());
223    }
224
225    /**
226     * Reserves space for stack-based outgoing arguments.
227     *
228     * @param argsSize The amount of space (in bytes) to reserve for stack-based outgoing arguments.
229     */
230    public void reserveOutgoing(int argsSize) {
231        assert frameSize == -1 : "frame size must not yet be fixed";
232        outgoingSize = Math.max(outgoingSize, argsSize);
233        hasOutgoingStackArguments = hasOutgoingStackArguments || argsSize > 0;
234    }
235
236    /**
237     * Reserves a new spill slot in the frame of the method being compiled. The returned slot is
238     * aligned on its natural alignment, i.e., an 8-byte spill slot is aligned at an 8-byte
239     * boundary.
240     *
241     * @param kind The kind of the spill slot to be reserved.
242     * @param additionalOffset
243     * @return A spill slot denoting the reserved memory area.
244     */
245    protected abstract StackSlot allocateNewSpillSlot(LIRKind kind, int additionalOffset);
246
247    /**
248     * Returns the spill slot size for the given {@link LIRKind}. The default value is the size in
249     * bytes for the target architecture.
250     *
251     * @param kind the {@link LIRKind} to be stored in the spill slot.
252     * @return the size in bytes
253     */
254    public int spillSlotSize(LIRKind kind) {
255        return getTarget().getSizeInBytes(kind.getPlatformKind());
256    }
257
258    /**
259     * Reserves a spill slot in the frame of the method being compiled. The returned slot is aligned
260     * on its natural alignment, i.e., an 8-byte spill slot is aligned at an 8-byte boundary, unless
261     * overridden by a subclass.
262     *
263     * @param kind The kind of the spill slot to be reserved.
264     * @return A spill slot denoting the reserved memory area.
265     */
266    public StackSlot allocateSpillSlot(LIRKind kind) {
267        assert frameSize == -1 : "frame size must not yet be fixed";
268        int size = spillSlotSize(kind);
269        spillSize = NumUtil.roundUp(spillSize + size, size);
270        return allocateNewSpillSlot(kind, 0);
271    }
272
273    /**
274     * Returns the size of the stack slot range for {@code slots} objects.
275     *
276     * @param slots The number of slots.
277     * @return The size in byte
278     */
279    public int spillSlotRangeSize(int slots) {
280        return slots * getTarget().wordSize;
281    }
282
283    /**
284     * Reserves a number of contiguous slots in the frame of the method being compiled. If the
285     * requested number of slots is 0, this method returns {@code null}.
286     *
287     * @param slots the number of slots to reserve
288     * @param objects specifies the indexes of the object pointer slots. The caller is responsible
289     *            for guaranteeing that each such object pointer slot is initialized before any
290     *            instruction that uses a reference map. Without this guarantee, the garbage
291     *            collector could see garbage object values.
292     * @return the first reserved stack slot (i.e., at the lowest address)
293     */
294    public StackSlot allocateStackSlots(int slots, BitSet objects) {
295        assert frameSize == -1 : "frame size must not yet be fixed";
296        if (slots == 0) {
297            return null;
298        }
299        spillSize += spillSlotRangeSize(slots);
300
301        if (!objects.isEmpty()) {
302            assert objects.length() <= slots;
303            StackSlot result = null;
304            for (int slotIndex = 0; slotIndex < slots; slotIndex++) {
305                StackSlot objectSlot = null;
306                if (objects.get(slotIndex)) {
307                    objectSlot = allocateNewSpillSlot(LIRKind.reference(Kind.Object), slotIndex * getTarget().wordSize);
308                    addObjectStackSlot(objectSlot);
309                }
310                if (slotIndex == 0) {
311                    if (objectSlot != null) {
312                        result = objectSlot;
313                    } else {
314                        result = allocateNewSpillSlot(LIRKind.value(getTarget().wordKind), 0);
315                    }
316                }
317            }
318            assert result != null;
319            return result;
320
321        } else {
322            return allocateNewSpillSlot(LIRKind.value(getTarget().wordKind), 0);
323        }
324    }
325
326    protected void addObjectStackSlot(StackSlot objectSlot) {
327        objectStackSlots.add(objectSlot);
328    }
329
330    public ReferenceMapBuilder newReferenceMapBuilder() {
331        return referenceMapFactory.newReferenceMapBuilder(totalFrameSize());
332    }
333}