31 |
31 |
32 import java.util.ArrayDeque; |
32 import java.util.ArrayDeque; |
33 import java.util.ArrayList; |
33 import java.util.ArrayList; |
34 import java.util.Arrays; |
34 import java.util.Arrays; |
35 import java.util.Deque; |
35 import java.util.Deque; |
36 import java.util.EnumMap; |
|
37 import java.util.EnumSet; |
36 import java.util.EnumSet; |
38 import java.util.PriorityQueue; |
37 import java.util.PriorityQueue; |
|
38 import java.util.function.Predicate; |
39 |
39 |
40 import jdk.internal.vm.compiler.collections.EconomicSet; |
40 import jdk.internal.vm.compiler.collections.EconomicSet; |
|
41 import org.graalvm.compiler.core.common.LIRKind; |
41 import org.graalvm.compiler.core.common.cfg.AbstractBlockBase; |
42 import org.graalvm.compiler.core.common.cfg.AbstractBlockBase; |
42 import org.graalvm.compiler.debug.DebugCloseable; |
43 import org.graalvm.compiler.debug.DebugCloseable; |
43 import org.graalvm.compiler.debug.DebugContext; |
44 import org.graalvm.compiler.debug.DebugContext; |
44 import org.graalvm.compiler.debug.Indent; |
45 import org.graalvm.compiler.debug.Indent; |
45 import org.graalvm.compiler.debug.TimerKey; |
46 import org.graalvm.compiler.debug.TimerKey; |
47 import org.graalvm.compiler.lir.LIRInstruction; |
48 import org.graalvm.compiler.lir.LIRInstruction; |
48 import org.graalvm.compiler.lir.LIRInstruction.OperandFlag; |
49 import org.graalvm.compiler.lir.LIRInstruction.OperandFlag; |
49 import org.graalvm.compiler.lir.LIRInstruction.OperandMode; |
50 import org.graalvm.compiler.lir.LIRInstruction.OperandMode; |
50 import org.graalvm.compiler.lir.ValueProcedure; |
51 import org.graalvm.compiler.lir.ValueProcedure; |
51 import org.graalvm.compiler.lir.VirtualStackSlot; |
52 import org.graalvm.compiler.lir.VirtualStackSlot; |
|
53 import org.graalvm.compiler.lir.framemap.FrameMap; |
52 import org.graalvm.compiler.lir.framemap.FrameMapBuilderTool; |
54 import org.graalvm.compiler.lir.framemap.FrameMapBuilderTool; |
53 import org.graalvm.compiler.lir.framemap.SimpleVirtualStackSlot; |
55 import org.graalvm.compiler.lir.framemap.SimpleVirtualStackSlot; |
54 import org.graalvm.compiler.lir.framemap.VirtualStackSlotRange; |
56 import org.graalvm.compiler.lir.framemap.VirtualStackSlotRange; |
55 import org.graalvm.compiler.lir.gen.LIRGenerationResult; |
57 import org.graalvm.compiler.lir.gen.LIRGenerationResult; |
56 import org.graalvm.compiler.lir.phases.AllocationPhase; |
58 import org.graalvm.compiler.lir.phases.AllocationPhase; |
57 import org.graalvm.compiler.options.NestedBooleanOptionKey; |
59 import org.graalvm.compiler.options.NestedBooleanOptionKey; |
58 import org.graalvm.compiler.options.Option; |
60 import org.graalvm.compiler.options.Option; |
59 import org.graalvm.compiler.options.OptionType; |
61 import org.graalvm.compiler.options.OptionType; |
60 |
62 |
|
63 import jdk.vm.ci.code.CodeUtil; |
61 import jdk.vm.ci.code.StackSlot; |
64 import jdk.vm.ci.code.StackSlot; |
62 import jdk.vm.ci.code.TargetDescription; |
65 import jdk.vm.ci.code.TargetDescription; |
63 import jdk.vm.ci.meta.Value; |
66 import jdk.vm.ci.meta.Value; |
64 import jdk.vm.ci.meta.ValueKind; |
67 import jdk.vm.ci.meta.ValueKind; |
65 |
68 |
154 if (debug.isDumpEnabled(DebugContext.VERBOSE_LEVEL)) { |
157 if (debug.isDumpEnabled(DebugContext.VERBOSE_LEVEL)) { |
155 dumpIntervals("Before stack slot allocation"); |
158 dumpIntervals("Before stack slot allocation"); |
156 } |
159 } |
157 // step 4: allocate stack slots |
160 // step 4: allocate stack slots |
158 try (DebugCloseable t = AllocateSlotsTimer.start(debug)) { |
161 try (DebugCloseable t = AllocateSlotsTimer.start(debug)) { |
159 allocateStackSlots(); |
162 /* |
|
163 * Allocate primitive spill slots before reference spill slots. This ensures a |
|
164 * ReferenceMap will be as compact as possible and only exceed the encoding limit of |
|
165 * a stack offset if there are really too many objects live on the stack at an |
|
166 * instruction with a ReferenceMap (as opposed to the method simply having a very |
|
167 * large frame). |
|
168 */ |
|
169 allocateStackSlots(IS_PRIMITIVE_INTERVAL); |
|
170 allocateStackSlots(IS_REFERENCE_INTERVAL); |
160 } |
171 } |
161 if (debug.isDumpEnabled(DebugContext.VERBOSE_LEVEL)) { |
172 if (debug.isDumpEnabled(DebugContext.VERBOSE_LEVEL)) { |
162 dumpIntervals("After stack slot allocation"); |
173 dumpIntervals("After stack slot allocation"); |
163 } |
174 } |
164 |
175 |
224 // ==================== |
235 // ==================== |
225 // step 4: allocate stack slots |
236 // step 4: allocate stack slots |
226 // ==================== |
237 // ==================== |
227 |
238 |
228 @SuppressWarnings("try") |
239 @SuppressWarnings("try") |
229 private void allocateStackSlots() { |
240 private void allocateStackSlots(Predicate<StackInterval> predicate) { |
230 // create unhandled lists |
|
231 for (StackInterval interval : stackSlotMap) { |
241 for (StackInterval interval : stackSlotMap) { |
232 if (interval != null) { |
242 if (interval != null && (predicate == null || predicate.test(interval))) { |
233 unhandled.add(interval); |
243 unhandled.add(interval); |
234 } |
244 } |
235 } |
245 } |
236 |
|
237 for (StackInterval current = activateNext(); current != null; current = activateNext()) { |
246 for (StackInterval current = activateNext(); current != null; current = activateNext()) { |
238 try (Indent indent = debug.logAndIndent("allocate %s", current)) { |
247 try (Indent indent = debug.logAndIndent("allocate %s", current)) { |
239 allocateSlot(current); |
248 allocateSlot(current); |
240 } |
249 } |
241 } |
250 } |
242 |
251 |
243 } |
252 // Cannot re-use free slots between rounds of slot allocation |
|
253 freeSlots = null; |
|
254 active.clear(); |
|
255 } |
|
256 |
|
257 private static final Predicate<StackInterval> IS_REFERENCE_INTERVAL = new Predicate<StackInterval>() { |
|
258 @Override |
|
259 public boolean test(StackInterval interval) { |
|
260 return !((LIRKind) interval.kind()).isValue(); |
|
261 } |
|
262 }; |
|
263 |
|
264 private static final Predicate<StackInterval> IS_PRIMITIVE_INTERVAL = new Predicate<StackInterval>() { |
|
265 @Override |
|
266 public boolean test(StackInterval interval) { |
|
267 return ((LIRKind) interval.kind()).isValue(); |
|
268 } |
|
269 }; |
244 |
270 |
245 private void allocateSlot(StackInterval current) { |
271 private void allocateSlot(StackInterval current) { |
246 VirtualStackSlot virtualSlot = current.getOperand(); |
272 VirtualStackSlot virtualSlot = current.getOperand(); |
247 final StackSlot location; |
273 final StackSlot location; |
248 if (virtualSlot instanceof VirtualStackSlotRange) { |
274 if (virtualSlot instanceof VirtualStackSlotRange) { |
249 // No reuse of ranges (yet). |
275 // No reuse of ranges (yet). |
250 VirtualStackSlotRange slotRange = (VirtualStackSlotRange) virtualSlot; |
276 VirtualStackSlotRange slotRange = (VirtualStackSlotRange) virtualSlot; |
251 location = frameMapBuilder.getFrameMap().allocateStackSlots(slotRange.getSlots(), slotRange.getObjects()); |
277 location = frameMapBuilder.getFrameMap().allocateStackSlots(slotRange.getSlots()); |
252 StackSlotAllocatorUtil.virtualFramesize.add(debug, frameMapBuilder.getFrameMap().spillSlotRangeSize(slotRange.getSlots())); |
278 StackSlotAllocatorUtil.virtualFramesize.add(debug, frameMapBuilder.getFrameMap().spillSlotRangeSize(slotRange.getSlots())); |
253 StackSlotAllocatorUtil.allocatedSlots.increment(debug); |
279 StackSlotAllocatorUtil.allocatedSlots.increment(debug); |
254 } else { |
280 } else { |
255 assert virtualSlot instanceof SimpleVirtualStackSlot : "Unexpected VirtualStackSlot type: " + virtualSlot; |
281 assert virtualSlot instanceof SimpleVirtualStackSlot : "Unexpected VirtualStackSlot type: " + virtualSlot; |
256 StackSlot slot = findFreeSlot((SimpleVirtualStackSlot) virtualSlot); |
282 StackSlot slot = findFreeSlot((SimpleVirtualStackSlot) virtualSlot); |
272 } |
298 } |
273 debug.log("Allocate location %s for interval %s", location, current); |
299 debug.log("Allocate location %s for interval %s", location, current); |
274 current.setLocation(location); |
300 current.setLocation(location); |
275 } |
301 } |
276 |
302 |
277 private enum SlotSize { |
303 /** |
278 Size1, |
304 * Map from log2 of {@link FrameMap#spillSlotSize(ValueKind) a spill slot size} to a list of |
279 Size2, |
305 * free stack slots. |
280 Size4, |
306 */ |
281 Size8, |
307 private ArrayList<Deque<StackSlot>> freeSlots; |
282 Illegal; |
308 |
283 } |
309 /** |
284 |
310 * @return The list of free stack slots for {@code index} or {@code null} if there is none. |
285 private SlotSize forKind(ValueKind<?> kind) { |
311 */ |
286 switch (frameMapBuilder.getFrameMap().spillSlotSize(kind)) { |
312 private Deque<StackSlot> getNullOrFreeSlots(int index) { |
287 case 1: |
|
288 return SlotSize.Size1; |
|
289 case 2: |
|
290 return SlotSize.Size2; |
|
291 case 4: |
|
292 return SlotSize.Size4; |
|
293 case 8: |
|
294 return SlotSize.Size8; |
|
295 default: |
|
296 return SlotSize.Illegal; |
|
297 } |
|
298 } |
|
299 |
|
300 private EnumMap<SlotSize, Deque<StackSlot>> freeSlots; |
|
301 |
|
302 /** |
|
303 * @return The list of free stack slots for {@code size} or {@code null} if there is none. |
|
304 */ |
|
305 private Deque<StackSlot> getOrNullFreeSlots(SlotSize size) { |
|
306 if (freeSlots == null) { |
313 if (freeSlots == null) { |
307 return null; |
314 return null; |
308 } |
315 } |
309 return freeSlots.get(size); |
316 if (index < freeSlots.size()) { |
310 } |
317 return freeSlots.get(index); |
311 |
318 } |
312 /** |
319 return null; |
313 * @return the list of free stack slots for {@code size}. If there is none a list is |
320 } |
|
321 |
|
322 /** |
|
323 * @return the list of free stack slots for {@code index}. If there is none a list is |
314 * created. |
324 * created. |
315 */ |
325 */ |
316 private Deque<StackSlot> getOrInitFreeSlots(SlotSize size) { |
326 private Deque<StackSlot> getOrInitFreeSlots(int index) { |
317 assert size != SlotSize.Illegal; |
327 Deque<StackSlot> freeList = null; |
318 Deque<StackSlot> freeList; |
328 if (freeSlots == null) { |
319 if (freeSlots != null) { |
329 freeSlots = new ArrayList<>(6); |
320 freeList = freeSlots.get(size); |
330 } else if (index < freeSlots.size()) { |
321 } else { |
331 freeList = freeSlots.get(index); |
322 freeSlots = new EnumMap<>(SlotSize.class); |
|
323 freeList = null; |
|
324 } |
332 } |
325 if (freeList == null) { |
333 if (freeList == null) { |
|
334 int requiredSize = index + 1; |
|
335 for (int i = freeSlots.size(); i < requiredSize; i++) { |
|
336 freeSlots.add(null); |
|
337 } |
326 freeList = new ArrayDeque<>(); |
338 freeList = new ArrayDeque<>(); |
327 freeSlots.put(size, freeList); |
339 freeSlots.set(index, freeList); |
328 } |
340 } |
329 assert freeList != null; |
|
330 return freeList; |
341 return freeList; |
331 } |
342 } |
332 |
343 |
333 /** |
344 /** |
334 * Gets a free stack slot for {@code slot} or {@code null} if there is none. |
345 * Gets a free stack slot for {@code slot} or {@code null} if there is none. |
335 */ |
346 */ |
336 private StackSlot findFreeSlot(SimpleVirtualStackSlot slot) { |
347 private StackSlot findFreeSlot(SimpleVirtualStackSlot slot) { |
337 assert slot != null; |
348 assert slot != null; |
338 SlotSize size = forKind(slot.getValueKind()); |
349 int size = log2SpillSlotSize(slot.getValueKind()); |
339 if (size == SlotSize.Illegal) { |
350 Deque<StackSlot> freeList = getNullOrFreeSlots(size); |
340 return null; |
|
341 } |
|
342 Deque<StackSlot> freeList = getOrNullFreeSlots(size); |
|
343 if (freeList == null) { |
351 if (freeList == null) { |
344 return null; |
352 return null; |
345 } |
353 } |
346 return freeList.pollLast(); |
354 return freeList.pollLast(); |
347 } |
355 } |
348 |
356 |
349 /** |
357 /** |
350 * Adds a stack slot to the list of free slots. |
358 * Adds a stack slot to the list of free slots. |
351 */ |
359 */ |
352 private void freeSlot(StackSlot slot) { |
360 private void freeSlot(StackSlot slot) { |
353 SlotSize size = forKind(slot.getValueKind()); |
361 int size = log2SpillSlotSize(slot.getValueKind()); |
354 if (size == SlotSize.Illegal) { |
|
355 return; |
|
356 } |
|
357 getOrInitFreeSlots(size).addLast(slot); |
362 getOrInitFreeSlots(size).addLast(slot); |
|
363 } |
|
364 |
|
365 private int log2SpillSlotSize(ValueKind<?> kind) { |
|
366 int size = frameMapBuilder.getFrameMap().spillSlotSize(kind); |
|
367 assert CodeUtil.isPowerOf2(size); |
|
368 return CodeUtil.log2(size); |
358 } |
369 } |
359 |
370 |
360 /** |
371 /** |
361 * Gets the next unhandled interval and finishes handled intervals. |
372 * Gets the next unhandled interval and finishes handled intervals. |
362 */ |
373 */ |