1 /*
   2  * Copyright (c) 2009, 2015, 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 org.graalvm.compiler.hotspot;
  24 
  25 import static jdk.vm.ci.code.ValueUtil.asRegister;
  26 import static jdk.vm.ci.code.ValueUtil.asStackSlot;
  27 import static jdk.vm.ci.code.ValueUtil.isRegister;
  28 import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant;
  29 
  30 import java.util.ArrayList;
  31 
  32 import org.graalvm.compiler.core.common.LIRKind;
  33 import org.graalvm.compiler.core.common.PermanentBailoutException;
  34 import org.graalvm.compiler.debug.GraalError;
  35 import org.graalvm.compiler.lir.LIRFrameState;
  36 import org.graalvm.compiler.lir.Variable;
  37 import org.graalvm.compiler.lir.framemap.ReferenceMapBuilder;
  38 
  39 import jdk.vm.ci.code.Location;
  40 import jdk.vm.ci.code.ReferenceMap;
  41 import jdk.vm.ci.code.StackSlot;
  42 import jdk.vm.ci.hotspot.HotSpotReferenceMap;
  43 import jdk.vm.ci.meta.PlatformKind;
  44 import jdk.vm.ci.meta.Value;
  45 
  46 public final class HotSpotReferenceMapBuilder extends ReferenceMapBuilder {
  47 
  48     private int maxRegisterSize;
  49 
  50     private final ArrayList<Value> objectValues;
  51     private int objectCount;
  52 
  53     private final int totalFrameSize;
  54     private final int maxOopMapStackOffset;
  55     private final int uncompressedReferenceSize;
  56 
  57     public HotSpotReferenceMapBuilder(int totalFrameSize, int maxOopMapStackOffset, int uncompressedReferenceSize) {
  58         this.uncompressedReferenceSize = uncompressedReferenceSize;
  59         this.objectValues = new ArrayList<>();
  60         this.objectCount = 0;
  61         this.maxOopMapStackOffset = maxOopMapStackOffset;
  62         this.totalFrameSize = totalFrameSize;
  63     }
  64 
  65     @Override
  66     public void addLiveValue(Value v) {
  67         if (isJavaConstant(v)) {
  68             return;
  69         }
  70         LIRKind lirKind = (LIRKind) v.getValueKind();
  71         if (!lirKind.isValue()) {
  72             objectValues.add(v);
  73             if (lirKind.isUnknownReference()) {
  74                 objectCount++;
  75             } else {
  76                 objectCount += lirKind.getReferenceCount();
  77             }
  78         }
  79         if (isRegister(v)) {
  80             int size = lirKind.getPlatformKind().getSizeInBytes();
  81             if (size > maxRegisterSize) {
  82                 maxRegisterSize = size;
  83             }
  84         }
  85     }
  86 
  87     private static final Location[] NO_LOCATIONS = {};
  88     private static final int[] NO_SIZES = {};
  89 
  90     @Override
  91     public ReferenceMap finish(LIRFrameState state) {
  92         Location[] objects;
  93         Location[] derivedBase;
  94         int[] sizeInBytes;
  95         if (objectCount == 0) {
  96             objects = NO_LOCATIONS;
  97             derivedBase = NO_LOCATIONS;
  98             sizeInBytes = NO_SIZES;
  99         } else {
 100             objects = new Location[objectCount];
 101             derivedBase = new Location[objectCount];
 102             sizeInBytes = new int[objectCount];
 103         }
 104         int idx = 0;
 105         for (Value obj : objectValues) {
 106             LIRKind kind = (LIRKind) obj.getValueKind();
 107             int bytes = bytesPerElement(kind);
 108             if (kind.isUnknownReference()) {
 109                 throw GraalError.shouldNotReachHere(String.format("unknown reference alive across safepoint: %s", obj));
 110             } else {
 111                 Location base = null;
 112                 if (kind.isDerivedReference()) {
 113                     Variable baseVariable = (Variable) kind.getDerivedReferenceBase();
 114                     Value baseValue = state.getLiveBasePointers().get(baseVariable.index);
 115                     assert baseValue.getPlatformKind().getVectorLength() == 1 && ((LIRKind) baseValue.getValueKind()).isReference(0) && !((LIRKind) baseValue.getValueKind()).isDerivedReference();
 116                     base = toLocation(baseValue, 0);
 117                 }
 118 
 119                 for (int i = 0; i < kind.getPlatformKind().getVectorLength(); i++) {
 120                     if (kind.isReference(i)) {
 121                         assert kind.isCompressedReference(i) ? (bytes < uncompressedReferenceSize) : (bytes == uncompressedReferenceSize);
 122                         objects[idx] = toLocation(obj, i * bytes);
 123                         derivedBase[idx] = base;
 124                         sizeInBytes[idx] = bytes;
 125                         idx++;
 126                     }
 127                 }
 128             }
 129         }
 130 
 131         return new HotSpotReferenceMap(objects, derivedBase, sizeInBytes, maxRegisterSize);
 132     }
 133 
 134     private static int bytesPerElement(LIRKind kind) {
 135         PlatformKind platformKind = kind.getPlatformKind();
 136         return platformKind.getSizeInBytes() / platformKind.getVectorLength();
 137     }
 138 
 139     private Location toLocation(Value v, int offset) {
 140         if (isRegister(v)) {
 141             return Location.subregister(asRegister(v), offset);
 142         } else {
 143             StackSlot s = asStackSlot(v);
 144             int totalOffset = s.getOffset(totalFrameSize) + offset;
 145             if (totalOffset > maxOopMapStackOffset) {
 146                 throw new PermanentBailoutException("stack offset %d for oopmap is greater than encoding limit %d", totalOffset, maxOopMapStackOffset);
 147             }
 148             return Location.stack(totalOffset);
 149         }
 150     }
 151 }