Mercurial > hg > truffle
comparison graal/Compiler/src/com/sun/c1x/lir/FrameMap.java @ 2507:9ec15d6914ca
Pull over of compiler from maxine repository.
author | Thomas Wuerthinger <thomas@wuerthinger.net> |
---|---|
date | Wed, 27 Apr 2011 11:43:22 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
2506:4a3bf8a5bf41 | 2507:9ec15d6914ca |
---|---|
1 /* | |
2 * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. | |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
4 * | |
5 * This code is free software; you can redistribute it and/or modify it | |
6 * under the terms of the GNU General Public License version 2 only, as | |
7 * published by the Free Software Foundation. | |
8 * | |
9 * This code is distributed in the hope that it will be useful, but WITHOUT | |
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
12 * version 2 for more details (a copy is included in the LICENSE file that | |
13 * accompanied this code). | |
14 * | |
15 * You should have received a copy of the GNU General Public License version | |
16 * 2 along with this work; if not, write to the Free Software Foundation, | |
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
18 * | |
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
20 * or visit www.oracle.com if you need additional information or have any | |
21 * questions. | |
22 */ | |
23 package com.sun.c1x.lir; | |
24 | |
25 import static com.sun.cri.ci.CiCallingConvention.Type.*; | |
26 import static com.sun.cri.ci.CiKind.*; | |
27 import static java.lang.reflect.Modifier.*; | |
28 | |
29 import com.sun.c1x.*; | |
30 import com.sun.c1x.globalstub.*; | |
31 import com.sun.c1x.util.*; | |
32 import com.sun.cri.bytecode.*; | |
33 import com.sun.cri.ci.*; | |
34 import com.sun.cri.ci.CiCallingConvention.Type; | |
35 import com.sun.cri.ri.*; | |
36 | |
37 /** | |
38 * This class is used to build the stack frame layout for a compiled method. | |
39 * | |
40 * This is the format of a stack frame on an x86 (i.e. IA32 or X64) platform: | |
41 * <pre> | |
42 * Base Contents | |
43 * | |
44 * : : | |
45 * | incoming overflow argument n | | |
46 * | ... | | |
47 * | incoming overflow argument 0 | | |
48 * | return address | Caller frame | |
49 * -------+--------------------------------+---------------- --- | |
50 * | | ^ | |
51 * : callee save area : | | |
52 * | | | | |
53 * +--------------------------------+ | | |
54 * | alignment padding | | | |
55 * +--------------------------------+ | | |
56 * | ALLOCA block n | | | |
57 * : ... : | | |
58 * | ALLOCA block 0 | Current frame | | |
59 * +--------------------------------+ | | |
60 * | monitor n | | | |
61 * : ... : | | |
62 * | monitor 0 | | | |
63 * +--------------------------------+ --- | | |
64 * | spill slot n | ^ frame | |
65 * : ... : | size | |
66 * | spill slot 0 | shared | | |
67 * +- - - - - - - - - - - - - - - - + slot | | |
68 * | outgoing overflow argument n | indexes | | |
69 * | ... | | | | |
70 * %sp | outgoing overflow argument 0 | v v | |
71 * -------+--------------------------------+---------------- --- | |
72 * | |
73 * </pre> | |
74 * Note that the size {@link Bytecodes#ALLOCA ALLOCA} blocks and {@code monitor}s in the frame may be greater | |
75 * than the size of a {@linkplain CiTarget#spillSlotSize spill slot}. | |
76 * | |
77 * @author Thomas Wuerthinger | |
78 * @author Ben L. Titzer | |
79 * @author Doug Simon | |
80 */ | |
81 public final class FrameMap { | |
82 | |
83 private final C1XCompilation compilation; | |
84 private final CiCallingConvention incomingArguments; | |
85 | |
86 /** | |
87 * Number of monitors used in this frame. | |
88 */ | |
89 private final int monitorCount; | |
90 | |
91 /** | |
92 * The final frame size. | |
93 * Value is only set after register allocation is complete. | |
94 */ | |
95 private int frameSize; | |
96 | |
97 /** | |
98 * The number of spill slots allocated by the register allocator. | |
99 * The value {@code -2} means that the size of outgoing argument stack slots | |
100 * is not yet fixed. The value {@code -1} means that the register | |
101 * allocator has started allocating spill slots and so the size of | |
102 * outgoing stack slots cannot change as outgoing stack slots and | |
103 * spill slots share the same slot index address space. | |
104 */ | |
105 private int spillSlotCount; | |
106 | |
107 /** | |
108 * The amount of memory allocated within the frame for uses of {@link Bytecodes#ALLOCA}. | |
109 */ | |
110 private int stackBlocksSize; | |
111 | |
112 /** | |
113 * Area occupied by outgoing overflow arguments. | |
114 * This value is adjusted as calling conventions for outgoing calls are retrieved. | |
115 */ | |
116 private int outgoingSize; | |
117 | |
118 /** | |
119 * Creates a new frame map for the specified method. | |
120 * | |
121 * @param compilation the compilation context | |
122 * @param method the outermost method being compiled | |
123 * @param monitors the number of monitors allocated on the stack for this method | |
124 */ | |
125 public FrameMap(C1XCompilation compilation, RiMethod method, int monitors) { | |
126 this.compilation = compilation; | |
127 this.frameSize = -1; | |
128 this.spillSlotCount = -2; | |
129 | |
130 assert monitors >= 0 : "not set"; | |
131 monitorCount = monitors; | |
132 if (method == null) { | |
133 incomingArguments = new CiCallingConvention(new CiValue[0], 0); | |
134 } else { | |
135 CiKind receiver = !isStatic(method.accessFlags()) ? method.holder().kind() : null; | |
136 incomingArguments = getCallingConvention(Util.signatureToKinds(method.signature(), receiver), JavaCallee); | |
137 } | |
138 } | |
139 | |
140 /** | |
141 * Gets the calling convention for a call with the specified signature. | |
142 * | |
143 * @param type the type of calling convention being requested | |
144 * @param signature the signature of the arguments | |
145 * @return a {@link CiCallingConvention} instance describing the location of parameters and the return value | |
146 */ | |
147 public CiCallingConvention getCallingConvention(CiKind[] signature, Type type) { | |
148 CiCallingConvention cc = compilation.registerConfig.getCallingConvention(type, signature, compilation.target); | |
149 if (type == RuntimeCall) { | |
150 assert cc.stackSize == 0 : "runtime call should not have stack arguments"; | |
151 } else if (type.out) { | |
152 assert frameSize == -1 : "frame size must not yet be fixed!"; | |
153 reserveOutgoing(cc.stackSize); | |
154 } | |
155 return cc; | |
156 } | |
157 | |
158 /** | |
159 * Gets the calling convention for the incoming arguments to the compiled method. | |
160 * @return the calling convention for incoming arguments | |
161 */ | |
162 public CiCallingConvention incomingArguments() { | |
163 return incomingArguments; | |
164 } | |
165 | |
166 /** | |
167 * Gets the frame size of the compiled frame. | |
168 * @return the size in bytes of the frame | |
169 */ | |
170 public int frameSize() { | |
171 assert this.frameSize != -1 : "frame size not computed yet"; | |
172 return frameSize; | |
173 } | |
174 | |
175 /** | |
176 * Sets the frame size for this frame. | |
177 * @param frameSize the frame size in bytes | |
178 */ | |
179 public void setFrameSize(int frameSize) { | |
180 assert this.frameSize == -1 : "should only be calculated once"; | |
181 this.frameSize = frameSize; | |
182 } | |
183 | |
184 /** | |
185 * Computes the frame size for this frame, given the number of spill slots. | |
186 * @param spillSlotCount the number of spill slots | |
187 */ | |
188 public void finalizeFrame(int spillSlotCount) { | |
189 assert this.spillSlotCount == -1 : "can only be set once"; | |
190 assert this.frameSize == -1 : "should only be calculated once"; | |
191 assert spillSlotCount >= 0 : "must be positive"; | |
192 | |
193 this.spillSlotCount = spillSlotCount; | |
194 int frameSize = offsetToStackBlocksEnd(); | |
195 frameSize += compilation.registerConfig.getCalleeSaveArea().size; | |
196 this.frameSize = compilation.target.alignFrameSize(frameSize); | |
197 } | |
198 | |
199 /** | |
200 * Informs the frame map that the compiled code uses a particular global stub, which | |
201 * may need stack space for outgoing arguments. | |
202 * | |
203 * @param stub the global stub | |
204 */ | |
205 public void usesGlobalStub(GlobalStub stub) { | |
206 reserveOutgoing(stub.argsSize); | |
207 } | |
208 | |
209 /** | |
210 * Converts a stack slot into a stack address. | |
211 * | |
212 * @param slot a stack slot | |
213 * @return a stack address | |
214 */ | |
215 public CiAddress toStackAddress(CiStackSlot slot) { | |
216 int size = compilation.target.sizeInBytes(slot.kind); | |
217 if (slot.inCallerFrame()) { | |
218 int offset = slot.index() * compilation.target.spillSlotSize; | |
219 return new CiAddress(slot.kind, CiRegister.CallerFrame.asValue(), offset); | |
220 } else { | |
221 int offset = offsetForOutgoingOrSpillSlot(slot.index(), size); | |
222 return new CiAddress(slot.kind, CiRegister.Frame.asValue(), offset); | |
223 } | |
224 } | |
225 | |
226 /** | |
227 * Gets the stack address within this frame for a given reserved stack block. | |
228 * | |
229 * @param stackBlock the value returned from {@link #reserveStackBlock(int)} identifying the stack block | |
230 * @return a representation of the stack location | |
231 */ | |
232 public CiAddress toStackAddress(StackBlock stackBlock) { | |
233 return new CiAddress(CiKind.Word, compilation.registerConfig.getFrameRegister().asValue(Word), offsetForStackBlock(stackBlock)); | |
234 } | |
235 | |
236 /** | |
237 * Converts the monitor index into the stack address of the object reference in the on-stack monitor. | |
238 * | |
239 * @param monitorIndex the monitor index | |
240 * @return a representation of the stack address | |
241 */ | |
242 public CiStackSlot toMonitorObjectStackAddress(int monitorIndex) { | |
243 int byteIndex = offsetForMonitorObject(monitorIndex); | |
244 assert byteIndex % compilation.target.wordSize == 0; | |
245 return CiStackSlot.get(CiKind.Object, byteIndex / compilation.target.wordSize); | |
246 } | |
247 | |
248 /** | |
249 * Converts the monitor index into the stack address of the on-stak monitor. | |
250 * | |
251 * @param monitorIndex the monitor index | |
252 * @return a representation of the stack address | |
253 */ | |
254 public CiStackSlot toMonitorBaseStackAddress(int monitorIndex) { | |
255 int byteIndex = offsetForMonitorBase(monitorIndex); | |
256 assert byteIndex % compilation.target.wordSize == 0; | |
257 return CiStackSlot.get(CiKind.Object, byteIndex / compilation.target.wordSize); | |
258 } | |
259 | |
260 /** | |
261 * Reserves space for stack-based outgoing arguments. | |
262 * | |
263 * @param argsSize the amount of space to reserve for stack-based outgoing arguments | |
264 */ | |
265 public void reserveOutgoing(int argsSize) { | |
266 assert spillSlotCount == -2 : "cannot reserve outgoing stack slot space once register allocation has started"; | |
267 if (argsSize > outgoingSize) { | |
268 outgoingSize = Util.roundUp(argsSize, compilation.target.spillSlotSize); | |
269 } | |
270 } | |
271 | |
272 /** | |
273 * Encapsulates the details of a stack block reserved by a call to {@link FrameMap#reserveStackBlock(int)}. | |
274 */ | |
275 public static final class StackBlock { | |
276 /** | |
277 * The size of this stack block. | |
278 */ | |
279 public final int size; | |
280 | |
281 /** | |
282 * The offset of this stack block within the frame space reserved for stack blocks. | |
283 */ | |
284 public final int offset; | |
285 | |
286 public StackBlock(int size, int offset) { | |
287 this.size = size; | |
288 this.offset = offset; | |
289 } | |
290 } | |
291 | |
292 /** | |
293 * Reserves a block of memory in the frame of the method being compiled. | |
294 * | |
295 * @param size the number of bytes to reserve | |
296 * @return a descriptor of the reserved block that can be used with {@link #toStackAddress(StackBlock)} once register | |
297 * allocation is complete and the size of the frame has been {@linkplain #finalizeFrame(int) finalized}. | |
298 */ | |
299 public StackBlock reserveStackBlock(int size) { | |
300 int wordSize = compilation.target.sizeInBytes(CiKind.Word); | |
301 assert (size % wordSize) == 0; | |
302 StackBlock block = new StackBlock(size, stackBlocksSize); | |
303 stackBlocksSize += size; | |
304 return block; | |
305 } | |
306 | |
307 private int offsetForStackBlock(StackBlock stackBlock) { | |
308 assert stackBlock.offset >= 0 && stackBlock.offset + stackBlock.size <= stackBlocksSize : "invalid stack block"; | |
309 int offset = offsetToStackBlocks() + stackBlock.offset; | |
310 assert offset <= (frameSize() - stackBlock.size) : "spill outside of frame"; | |
311 return offset; | |
312 } | |
313 | |
314 /** | |
315 * Gets the stack pointer offset for a outgoing stack argument or compiler spill slot. | |
316 * | |
317 * @param slotIndex the index of the stack slot within the slot index space reserved for | |
318 * @param size | |
319 * @return | |
320 */ | |
321 private int offsetForOutgoingOrSpillSlot(int slotIndex, int size) { | |
322 assert slotIndex >= 0 && slotIndex < (initialSpillSlot() + spillSlotCount) : "invalid spill slot"; | |
323 int offset = slotIndex * compilation.target.spillSlotSize; | |
324 assert offset <= (frameSize() - size) : "slot outside of frame"; | |
325 return offset; | |
326 } | |
327 | |
328 private int offsetForMonitorBase(int index) { | |
329 assert index >= 0 && index < monitorCount : "invalid monitor index"; | |
330 int size = compilation.runtime.sizeOfBasicObjectLock(); | |
331 assert size != 0 : "monitors are not on the stack in this VM"; | |
332 int offset = offsetToMonitors() + index * size; | |
333 assert offset <= (frameSize() - size) : "monitor outside of frame"; | |
334 return offset; | |
335 } | |
336 | |
337 private int offsetToSpillArea() { | |
338 return outgoingSize; | |
339 } | |
340 | |
341 private int offsetToSpillEnd() { | |
342 return offsetToSpillArea() + spillSlotCount * compilation.target.spillSlotSize; | |
343 } | |
344 | |
345 private int offsetToMonitors() { | |
346 return offsetToCustomArea() + customAreaSize(); | |
347 } | |
348 | |
349 public int customAreaSize() { | |
350 return compilation.runtime.getCustomStackAreaSize(); | |
351 } | |
352 | |
353 public int offsetToCustomArea() { | |
354 return offsetToSpillEnd(); | |
355 } | |
356 | |
357 private int offsetToMonitorsEnd() { | |
358 return offsetToMonitors() + (monitorCount * compilation.runtime.sizeOfBasicObjectLock()); | |
359 } | |
360 | |
361 private int offsetToStackBlocks() { | |
362 return offsetToMonitorsEnd(); | |
363 } | |
364 | |
365 private int offsetToStackBlocksEnd() { | |
366 return offsetToStackBlocks() + stackBlocksSize; | |
367 } | |
368 | |
369 public int offsetToCalleeSaveAreaStart() { | |
370 return offsetToCalleeSaveAreaEnd() - compilation.registerConfig.getCalleeSaveArea().size; | |
371 } | |
372 | |
373 public int offsetToCalleeSaveAreaEnd() { | |
374 return frameSize; | |
375 } | |
376 | |
377 private int offsetForMonitorObject(int index) { | |
378 return offsetForMonitorBase(index) + compilation.runtime.basicObjectLockOffsetInBytes(); | |
379 } | |
380 | |
381 /** | |
382 * Gets the index of the first available spill slot relative to the base of the frame. | |
383 * After this call, no further outgoing stack slots can be {@linkplain #reserveOutgoing(int) reserved}. | |
384 * | |
385 * @return the index of the first available spill slot | |
386 */ | |
387 public int initialSpillSlot() { | |
388 if (spillSlotCount == -2) { | |
389 spillSlotCount = -1; | |
390 } | |
391 return outgoingSize / compilation.target.spillSlotSize; | |
392 } | |
393 | |
394 } |