comparison graal/com.oracle.jvmci.hotspot/src/com/oracle/jvmci/hotspot/HotSpotReferenceMap.java @ 21551:5324104ac4f3

moved com.oracle.graal.hotspot.jvmci classes to com.oracle.jvmci.hotspot module (JBS:GRAAL-53)
author Doug Simon <doug.simon@oracle.com>
date Tue, 26 May 2015 17:13:37 +0200
parents
children
comparison
equal deleted inserted replaced
21550:f48a6cea31eb 21551:5324104ac4f3
1 /*
2 * Copyright (c) 2009, 2014, 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 com.oracle.jvmci.hotspot;
24
25 import java.util.*;
26
27 import com.oracle.graal.api.code.CodeUtil.RefMapFormatter;
28 import com.oracle.graal.api.code.*;
29 import com.oracle.graal.api.meta.*;
30 import com.oracle.jvmci.common.*;
31
32 public final class HotSpotReferenceMap extends ReferenceMap {
33
34 static final int OOP64 = 0b1010;
35 static final int OOP32 = 0b01;
36 static final int NARROW_LOW = OOP32;
37 static final int NARROW_HIGH = OOP32 << 2;
38 static final int NARROW_BOTH = NARROW_LOW | NARROW_HIGH;
39
40 private enum MapEntry {
41 NoReference(0),
42 WideOop(OOP64),
43 NarrowOopLowerHalf(NARROW_LOW),
44 NarrowOopUpperHalf(NARROW_HIGH),
45 TwoNarrowOops(NARROW_BOTH),
46 Illegal(-1);
47
48 MapEntry(int pattern) {
49 this.pattern = pattern;
50 }
51
52 final int pattern;
53
54 /**
55 * Create enum values from OopMap.
56 * <p>
57 * These bits can have the following values (MSB first):
58 *
59 * <pre>
60 * 0000 - contains no references
61 * 1010 - contains a wide oop
62 * 0001 - contains a narrow oop in the lower half
63 * 0101 - contains a narrow oop in the upper half
64 * 0101 - contains two narrow oops
65 * </pre>
66 *
67 * @see HotSpotReferenceMap#registerRefMap
68 * @see HotSpotReferenceMap#frameRefMap
69 */
70 static MapEntry getFromBits(int idx, HotSpotOopMap set) {
71 int n = set.get(idx);
72 switch (n) {
73 case 0:
74 return NoReference;
75 case OOP64:
76 return WideOop;
77 case NARROW_LOW:
78 return NarrowOopLowerHalf;
79 case NARROW_HIGH:
80 return NarrowOopUpperHalf;
81 case NARROW_BOTH:
82 return TwoNarrowOops;
83 default:
84 return Illegal;
85 }
86 }
87
88 String toBitString() {
89 int bits = toBit(this);
90 if (bits == -1) {
91 return "---";
92 }
93 return String.format("%3s", Integer.toBinaryString(bits)).replace(' ', '0');
94 }
95
96 static int toBit(MapEntry type) {
97 return type.pattern;
98 }
99 }
100
101 /**
102 * A specialized bit set that represents both wide and narrow oops in an efficient manner. The
103 * map consists of 4 bit entries that represent 8 bytes of memory.
104 *
105 */
106 class HotSpotOopMap implements Cloneable {
107
108 /**
109 * Each entry is 4 bits long and covers 8 bytes of memory.
110 */
111 private static final int BITS_PER_ENTRY = 4;
112 private static final int BITS_PER_ELEMENT = 64;
113
114 public HotSpotOopMap(int i) {
115 words = new long[(i * BITS_PER_ENTRY + BITS_PER_ELEMENT) / BITS_PER_ELEMENT];
116 }
117
118 public HotSpotOopMap(HotSpotOopMap other) {
119 words = other.words.clone();
120 }
121
122 private long[] words;
123
124 private int get(int i) {
125 return getEntry(i);
126 }
127
128 public void or(HotSpotOopMap src) {
129 if (words.length < src.words.length) {
130 long[] newWords = new long[src.words.length];
131 System.arraycopy(src.words, 0, newWords, 0, src.words.length);
132 for (int i = 0; i < words.length; i++) {
133 newWords[i] |= words[i];
134 }
135 words = newWords;
136 } else {
137 for (int i = 0; i < src.words.length; i++) {
138 words[i] |= src.words[i];
139 }
140 }
141 }
142
143 private void setOop(int regIdx) {
144 setEntry(regIdx, OOP64);
145 }
146
147 public int size() {
148 return words.length * BITS_PER_ELEMENT / BITS_PER_ENTRY;
149 }
150
151 @Override
152 public HotSpotOopMap clone() {
153 return new HotSpotOopMap(this);
154 }
155
156 private void setNarrowOop(int offset) {
157 setNarrowEntry(offset, OOP32);
158 }
159
160 private void setEntry(int regIdx, int value) {
161 assert regIdx % 2 == 0 : "must be alinged";
162 int bitIndex = (regIdx >> 1) * BITS_PER_ENTRY;
163 int wordIndex = bitIndex / BITS_PER_ELEMENT;
164 int shift = bitIndex - wordIndex * BITS_PER_ELEMENT;
165 if (wordIndex >= words.length) {
166 if (value == 0) {
167 // Nothing to do since bits are clear
168 return;
169 }
170 words = Arrays.copyOf(words, wordIndex + 1);
171 }
172 assert verifyUpdate(this, this);
173 long orig = words[wordIndex];
174 words[wordIndex] = (orig & (~(0b1111L << shift))) | ((long) value << shift);
175 assert get(regIdx / 2) == value;
176 assert verifyUpdate(this, this);
177 }
178
179 private void setNarrowEntry(int offset, int value) {
180 int regIdx = offset >> 1;
181 boolean low = offset % 2 == 0;
182 int bitIndex = regIdx * BITS_PER_ENTRY;
183 int wordIndex = bitIndex / BITS_PER_ELEMENT;
184 int shift = bitIndex - wordIndex * BITS_PER_ELEMENT;
185 if (wordIndex >= words.length) {
186 if (value == 0) {
187 // Nothing to do since bits are clear
188 return;
189 }
190 words = Arrays.copyOf(words, wordIndex + 1);
191 }
192 long originalValue = words[wordIndex];
193 int current = ((int) (originalValue >> shift)) & 0b1111;
194 if (current == OOP64) {
195 current = 0;
196 }
197 long newValue;
198 if (value != 0) {
199 newValue = current | (low ? value : (value << 2));
200 } else {
201 newValue = current & (low ? 0b1100 : 0b0011);
202 }
203 long masked = originalValue & (~(0b1111L << shift));
204 words[wordIndex] = masked | (newValue << shift);
205 assert verifyUpdate(this, this);
206 }
207
208 private int getEntry(int regIdx) {
209 int bitIndex = regIdx * BITS_PER_ENTRY;
210 int wordIndex = bitIndex / BITS_PER_ELEMENT;
211 int shift = bitIndex - wordIndex * BITS_PER_ELEMENT;
212 return ((int) (words[wordIndex] >>> shift)) & 0b1111;
213 }
214
215 @Override
216 public boolean equals(Object other) {
217 if (this == other) {
218 return true;
219 }
220
221 if (other instanceof HotSpotOopMap) {
222 HotSpotOopMap otherMap = (HotSpotOopMap) other;
223 int limit = Math.min(words.length, otherMap.words.length);
224 for (int i = 0; i < limit; i++) {
225 if (words[i] != otherMap.words[i]) {
226 return false;
227 }
228 }
229 for (int i = limit; i < words.length; i++) {
230 if (words[i] != 0) {
231 return false;
232 }
233 }
234 for (int i = limit; i < otherMap.words.length; i++) {
235 if (otherMap.words[i] != 0) {
236 return false;
237 }
238 }
239 return true;
240 }
241 return false;
242 }
243
244 @Override
245 public int hashCode() {
246 long h = 1234;
247 for (int i = words.length; --i >= 0;) {
248 h ^= words[i] * (i + 1);
249 }
250 return (int) ((h >> 32) ^ h);
251 }
252
253 @Override
254 public String toString() {
255 int count = 0;
256 StringBuilder sb = new StringBuilder();
257 sb.append("[");
258 for (int idx = 0; idx < size(); idx++) {
259 MapEntry dstType = MapEntry.getFromBits(idx, this);
260 if (dstType == MapEntry.NoReference) {
261 continue;
262 }
263 if (count > 0) {
264 sb.append(", ");
265 }
266 if (dstType == MapEntry.Illegal) {
267 int value = get(idx);
268 sb.append("0x");
269 sb.append(Integer.toHexString(value));
270 } else {
271 sb.append(idx);
272 sb.append(':');
273 sb.append(dstType);
274 }
275 count++;
276 }
277 sb.append("]");
278 return sb.toString();
279 }
280 }
281
282 /**
283 * Contains 3 bits per scalar register, and n*3 bits per n-word vector register (e.g., on a
284 * 64-bit system, a 256-bit vector register requires 12 reference map bits).
285 * <p>
286 * These bits can have the following values (LSB first):
287 *
288 * <pre>
289 * 000 - contains no references
290 * 100 - contains a wide oop
291 * 110 - contains a narrow oop in the lower half
292 * 101 - contains a narrow oop in the upper half
293 * 111 - contains two narrow oops
294 * </pre>
295 */
296 private final HotSpotOopMap registerRefMap;
297
298 /**
299 * Contains 3 bits per stack word.
300 * <p>
301 * These bits can have the following values (LSB first):
302 *
303 * <pre>
304 * 000 - contains no references
305 * 100 - contains a wide oop
306 * 110 - contains a narrow oop in the lower half
307 * 101 - contains a narrow oop in the upper half
308 * 111 - contains two narrow oops
309 * </pre>
310 */
311 private final HotSpotOopMap frameRefMap;
312
313 private final TargetDescription target;
314
315 public HotSpotReferenceMap(int registerCount, int frameSlotCount, TargetDescription target) {
316 if (registerCount > 0) {
317 this.registerRefMap = new HotSpotOopMap(registerCount);
318 } else {
319 this.registerRefMap = null;
320 }
321 this.frameRefMap = new HotSpotOopMap(frameSlotCount);
322 this.target = target;
323 }
324
325 private HotSpotReferenceMap(HotSpotReferenceMap other) {
326 this.registerRefMap = other.registerRefMap.clone();
327 this.frameRefMap = other.frameRefMap.clone();
328 this.target = other.target;
329 }
330
331 @Override
332 public ReferenceMap clone() {
333 return new HotSpotReferenceMap(this);
334 }
335
336 // setters
337 @Override
338 public void setRegister(int idx, LIRKind kind) {
339 set(registerRefMap, idx * 2, kind);
340 }
341
342 @Override
343 public void setStackSlot(int offset, LIRKind kind) {
344 assert offset % bytesPerElement(kind) == 0 : "unaligned value in ReferenceMap";
345 set(frameRefMap, offset / 4, kind);
346 }
347
348 private void set(HotSpotOopMap refMap, int index, LIRKind kind) {
349 if (kind.isDerivedReference()) {
350 throw new JVMCIError("derived reference cannot be inserted in ReferenceMap");
351 }
352
353 int bytesPerElement = bytesPerElement(kind);
354 int length = kind.getPlatformKind().getVectorLength();
355 if (bytesPerElement == 8) {
356 for (int i = 0; i < length; i++) {
357 if (kind.isReference(i)) {
358 refMap.setOop(index + i * 2);
359 }
360 }
361 } else if (bytesPerElement == 4) {
362 for (int i = 0; i < length; i++) {
363 if (kind.isReference(i)) {
364 refMap.setNarrowOop(index + i);
365 }
366 }
367 } else {
368 assert kind.isValue() : "unknown reference kind " + kind;
369 }
370 }
371
372 private int bytesPerElement(LIRKind kind) {
373 PlatformKind platformKind = kind.getPlatformKind();
374 return target.getSizeInBytes(platformKind) / platformKind.getVectorLength();
375 }
376
377 public HotSpotOopMap getFrameMap() {
378 return frameRefMap == null ? null : (HotSpotOopMap) frameRefMap.clone();
379 }
380
381 public HotSpotOopMap getRegisterMap() {
382 return registerRefMap == null ? null : (HotSpotOopMap) registerRefMap.clone();
383 }
384
385 static MapEntry[] entries(HotSpotOopMap fixedMap) {
386 MapEntry[] result = new MapEntry[fixedMap.size()];
387 for (int idx = 0; idx < fixedMap.size(); idx++) {
388 MapEntry dstType = MapEntry.getFromBits(idx, fixedMap);
389 result[idx] = dstType;
390 }
391 return result;
392 }
393
394 private static boolean verifyUpdate(HotSpotOopMap dst, HotSpotOopMap src) {
395 return verifyUpdate(dst, src, true);
396 }
397
398 private static boolean verifyUpdate(HotSpotOopMap dst, HotSpotOopMap src, boolean doAssert) {
399 for (int idx = 0; idx < Math.min(src.size(), dst.size()); idx++) {
400 if (!verifyUpdateEntry(idx, dst, src, doAssert)) {
401 return false;
402 }
403 }
404 return true;
405 }
406
407 private static boolean verifyUpdateEntry(int idx, HotSpotOopMap dst, HotSpotOopMap src, boolean doAssert) {
408 MapEntry dstType = MapEntry.getFromBits(idx, dst);
409 MapEntry srcType = MapEntry.getFromBits(idx, src);
410
411 if (dstType == MapEntry.Illegal || srcType == MapEntry.Illegal) {
412 assert !doAssert : String.format("Illegal RefMap bit pattern: %s (0b%s), %s (0b%s)", dstType, dstType.toBitString(), srcType, srcType.toBitString());
413 return false;
414 }
415 switch (dstType) {
416 case NoReference:
417 return true;
418 case WideOop:
419 switch (srcType) {
420 case NoReference:
421 case WideOop:
422 return true;
423 default:
424 assert false : String.format("Illegal RefMap combination: %s (0b%s), %s (0b%s)", dstType, dstType.toBitString(), srcType, srcType.toBitString());
425 return false;
426 }
427 case TwoNarrowOops:
428 case NarrowOopLowerHalf:
429 case NarrowOopUpperHalf:
430 switch (srcType) {
431 case TwoNarrowOops:
432 case NarrowOopLowerHalf:
433 case NarrowOopUpperHalf:
434 case NoReference:
435 return true;
436 default:
437 assert false : String.format("Illegal RefMap combination: %s (0b%s), %s (0b%s)", dstType, dstType.toBitString(), srcType, srcType.toBitString());
438 return false;
439 }
440 default:
441 return false;
442 }
443 }
444
445 @Override
446 public int hashCode() {
447 throw new UnsupportedOperationException();
448 }
449
450 @Override
451 public boolean equals(Object obj) {
452 if (this == obj) {
453 return true;
454 }
455 if (obj instanceof HotSpotReferenceMap) {
456 HotSpotReferenceMap that = (HotSpotReferenceMap) obj;
457 if (this.frameRefMap.equals(that.frameRefMap) && Objects.equals(this.registerRefMap, that.registerRefMap) && this.target.equals(that.target)) {
458 return true;
459 }
460 }
461 return false;
462 }
463
464 @Override
465 public boolean hasRegisterRefMap() {
466 return registerRefMap != null && registerRefMap.size() > 0;
467 }
468
469 @Override
470 public boolean hasFrameRefMap() {
471 return frameRefMap != null && frameRefMap.size() > 0;
472 }
473
474 @Override
475 public void appendRegisterMap(StringBuilder sb, RefMapFormatter formatter) {
476 for (int idx = 0; idx < registerRefMap.size(); idx++) {
477 MapEntry dstType = MapEntry.getFromBits(idx, registerRefMap);
478 if (dstType != MapEntry.NoReference) {
479 sb.append(' ').append(formatter.formatRegister(idx)).append(':').append(dstType);
480 }
481 }
482 }
483
484 @Override
485 public void appendFrameMap(StringBuilder sb, RefMapFormatter formatter) {
486 for (int idx = 0; idx < frameRefMap.size(); idx++) {
487 MapEntry dstType = MapEntry.getFromBits(idx, frameRefMap);
488 if (dstType != MapEntry.NoReference) {
489 sb.append(' ').append(formatter.formatStackSlot(idx)).append(':').append(dstType);
490 }
491 }
492 }
493
494 @Override
495 public String toString() {
496 StringBuilder sb = new StringBuilder();
497 if (registerRefMap != null) {
498 sb.append("Registers = ");
499 sb.append(registerRefMap);
500 }
501 sb.append("Stack = ");
502 sb.append(frameRefMap);
503 return sb.toString();
504 }
505
506 public void verify() {
507 assert verifyUpdate(frameRefMap, frameRefMap);
508 assert registerRefMap == null || verifyUpdate(registerRefMap, registerRefMap);
509 }
510 }