src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/stackslotalloc/LSStackSlotAllocator.java
branchdatagramsocketimpl-branch
changeset 58678 9cf78a70fa4f
parent 52910 583fd71c47d6
child 58679 9c3209ff7550
equal deleted inserted replaced
58677:13588c901957 58678:9cf78a70fa4f
     1 /*
     1 /*
     2  * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
     2  * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     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
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.
     7  * published by the Free Software Foundation.
    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          */