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