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