Mercurial > hg > graal-compiler
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.jvmci.hotspot/src/com/oracle/jvmci/hotspot/HotSpotReferenceMap.java Tue May 26 17:13:37 2015 +0200 @@ -0,0 +1,510 @@ +/* + * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.jvmci.hotspot; + +import java.util.*; + +import com.oracle.graal.api.code.CodeUtil.RefMapFormatter; +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.jvmci.common.*; + +public final class HotSpotReferenceMap extends ReferenceMap { + + static final int OOP64 = 0b1010; + static final int OOP32 = 0b01; + static final int NARROW_LOW = OOP32; + static final int NARROW_HIGH = OOP32 << 2; + static final int NARROW_BOTH = NARROW_LOW | NARROW_HIGH; + + private enum MapEntry { + NoReference(0), + WideOop(OOP64), + NarrowOopLowerHalf(NARROW_LOW), + NarrowOopUpperHalf(NARROW_HIGH), + TwoNarrowOops(NARROW_BOTH), + Illegal(-1); + + MapEntry(int pattern) { + this.pattern = pattern; + } + + final int pattern; + + /** + * Create enum values from OopMap. + * <p> + * These bits can have the following values (MSB first): + * + * <pre> + * 0000 - contains no references + * 1010 - contains a wide oop + * 0001 - contains a narrow oop in the lower half + * 0101 - contains a narrow oop in the upper half + * 0101 - contains two narrow oops + * </pre> + * + * @see HotSpotReferenceMap#registerRefMap + * @see HotSpotReferenceMap#frameRefMap + */ + static MapEntry getFromBits(int idx, HotSpotOopMap set) { + int n = set.get(idx); + switch (n) { + case 0: + return NoReference; + case OOP64: + return WideOop; + case NARROW_LOW: + return NarrowOopLowerHalf; + case NARROW_HIGH: + return NarrowOopUpperHalf; + case NARROW_BOTH: + return TwoNarrowOops; + default: + return Illegal; + } + } + + String toBitString() { + int bits = toBit(this); + if (bits == -1) { + return "---"; + } + return String.format("%3s", Integer.toBinaryString(bits)).replace(' ', '0'); + } + + static int toBit(MapEntry type) { + return type.pattern; + } + } + + /** + * A specialized bit set that represents both wide and narrow oops in an efficient manner. The + * map consists of 4 bit entries that represent 8 bytes of memory. + * + */ + class HotSpotOopMap implements Cloneable { + + /** + * Each entry is 4 bits long and covers 8 bytes of memory. + */ + private static final int BITS_PER_ENTRY = 4; + private static final int BITS_PER_ELEMENT = 64; + + public HotSpotOopMap(int i) { + words = new long[(i * BITS_PER_ENTRY + BITS_PER_ELEMENT) / BITS_PER_ELEMENT]; + } + + public HotSpotOopMap(HotSpotOopMap other) { + words = other.words.clone(); + } + + private long[] words; + + private int get(int i) { + return getEntry(i); + } + + public void or(HotSpotOopMap src) { + if (words.length < src.words.length) { + long[] newWords = new long[src.words.length]; + System.arraycopy(src.words, 0, newWords, 0, src.words.length); + for (int i = 0; i < words.length; i++) { + newWords[i] |= words[i]; + } + words = newWords; + } else { + for (int i = 0; i < src.words.length; i++) { + words[i] |= src.words[i]; + } + } + } + + private void setOop(int regIdx) { + setEntry(regIdx, OOP64); + } + + public int size() { + return words.length * BITS_PER_ELEMENT / BITS_PER_ENTRY; + } + + @Override + public HotSpotOopMap clone() { + return new HotSpotOopMap(this); + } + + private void setNarrowOop(int offset) { + setNarrowEntry(offset, OOP32); + } + + private void setEntry(int regIdx, int value) { + assert regIdx % 2 == 0 : "must be alinged"; + int bitIndex = (regIdx >> 1) * BITS_PER_ENTRY; + int wordIndex = bitIndex / BITS_PER_ELEMENT; + int shift = bitIndex - wordIndex * BITS_PER_ELEMENT; + if (wordIndex >= words.length) { + if (value == 0) { + // Nothing to do since bits are clear + return; + } + words = Arrays.copyOf(words, wordIndex + 1); + } + assert verifyUpdate(this, this); + long orig = words[wordIndex]; + words[wordIndex] = (orig & (~(0b1111L << shift))) | ((long) value << shift); + assert get(regIdx / 2) == value; + assert verifyUpdate(this, this); + } + + private void setNarrowEntry(int offset, int value) { + int regIdx = offset >> 1; + boolean low = offset % 2 == 0; + int bitIndex = regIdx * BITS_PER_ENTRY; + int wordIndex = bitIndex / BITS_PER_ELEMENT; + int shift = bitIndex - wordIndex * BITS_PER_ELEMENT; + if (wordIndex >= words.length) { + if (value == 0) { + // Nothing to do since bits are clear + return; + } + words = Arrays.copyOf(words, wordIndex + 1); + } + long originalValue = words[wordIndex]; + int current = ((int) (originalValue >> shift)) & 0b1111; + if (current == OOP64) { + current = 0; + } + long newValue; + if (value != 0) { + newValue = current | (low ? value : (value << 2)); + } else { + newValue = current & (low ? 0b1100 : 0b0011); + } + long masked = originalValue & (~(0b1111L << shift)); + words[wordIndex] = masked | (newValue << shift); + assert verifyUpdate(this, this); + } + + private int getEntry(int regIdx) { + int bitIndex = regIdx * BITS_PER_ENTRY; + int wordIndex = bitIndex / BITS_PER_ELEMENT; + int shift = bitIndex - wordIndex * BITS_PER_ELEMENT; + return ((int) (words[wordIndex] >>> shift)) & 0b1111; + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + + if (other instanceof HotSpotOopMap) { + HotSpotOopMap otherMap = (HotSpotOopMap) other; + int limit = Math.min(words.length, otherMap.words.length); + for (int i = 0; i < limit; i++) { + if (words[i] != otherMap.words[i]) { + return false; + } + } + for (int i = limit; i < words.length; i++) { + if (words[i] != 0) { + return false; + } + } + for (int i = limit; i < otherMap.words.length; i++) { + if (otherMap.words[i] != 0) { + return false; + } + } + return true; + } + return false; + } + + @Override + public int hashCode() { + long h = 1234; + for (int i = words.length; --i >= 0;) { + h ^= words[i] * (i + 1); + } + return (int) ((h >> 32) ^ h); + } + + @Override + public String toString() { + int count = 0; + StringBuilder sb = new StringBuilder(); + sb.append("["); + for (int idx = 0; idx < size(); idx++) { + MapEntry dstType = MapEntry.getFromBits(idx, this); + if (dstType == MapEntry.NoReference) { + continue; + } + if (count > 0) { + sb.append(", "); + } + if (dstType == MapEntry.Illegal) { + int value = get(idx); + sb.append("0x"); + sb.append(Integer.toHexString(value)); + } else { + sb.append(idx); + sb.append(':'); + sb.append(dstType); + } + count++; + } + sb.append("]"); + return sb.toString(); + } + } + + /** + * Contains 3 bits per scalar register, and n*3 bits per n-word vector register (e.g., on a + * 64-bit system, a 256-bit vector register requires 12 reference map bits). + * <p> + * These bits can have the following values (LSB first): + * + * <pre> + * 000 - contains no references + * 100 - contains a wide oop + * 110 - contains a narrow oop in the lower half + * 101 - contains a narrow oop in the upper half + * 111 - contains two narrow oops + * </pre> + */ + private final HotSpotOopMap registerRefMap; + + /** + * Contains 3 bits per stack word. + * <p> + * These bits can have the following values (LSB first): + * + * <pre> + * 000 - contains no references + * 100 - contains a wide oop + * 110 - contains a narrow oop in the lower half + * 101 - contains a narrow oop in the upper half + * 111 - contains two narrow oops + * </pre> + */ + private final HotSpotOopMap frameRefMap; + + private final TargetDescription target; + + public HotSpotReferenceMap(int registerCount, int frameSlotCount, TargetDescription target) { + if (registerCount > 0) { + this.registerRefMap = new HotSpotOopMap(registerCount); + } else { + this.registerRefMap = null; + } + this.frameRefMap = new HotSpotOopMap(frameSlotCount); + this.target = target; + } + + private HotSpotReferenceMap(HotSpotReferenceMap other) { + this.registerRefMap = other.registerRefMap.clone(); + this.frameRefMap = other.frameRefMap.clone(); + this.target = other.target; + } + + @Override + public ReferenceMap clone() { + return new HotSpotReferenceMap(this); + } + + // setters + @Override + public void setRegister(int idx, LIRKind kind) { + set(registerRefMap, idx * 2, kind); + } + + @Override + public void setStackSlot(int offset, LIRKind kind) { + assert offset % bytesPerElement(kind) == 0 : "unaligned value in ReferenceMap"; + set(frameRefMap, offset / 4, kind); + } + + private void set(HotSpotOopMap refMap, int index, LIRKind kind) { + if (kind.isDerivedReference()) { + throw new JVMCIError("derived reference cannot be inserted in ReferenceMap"); + } + + int bytesPerElement = bytesPerElement(kind); + int length = kind.getPlatformKind().getVectorLength(); + if (bytesPerElement == 8) { + for (int i = 0; i < length; i++) { + if (kind.isReference(i)) { + refMap.setOop(index + i * 2); + } + } + } else if (bytesPerElement == 4) { + for (int i = 0; i < length; i++) { + if (kind.isReference(i)) { + refMap.setNarrowOop(index + i); + } + } + } else { + assert kind.isValue() : "unknown reference kind " + kind; + } + } + + private int bytesPerElement(LIRKind kind) { + PlatformKind platformKind = kind.getPlatformKind(); + return target.getSizeInBytes(platformKind) / platformKind.getVectorLength(); + } + + public HotSpotOopMap getFrameMap() { + return frameRefMap == null ? null : (HotSpotOopMap) frameRefMap.clone(); + } + + public HotSpotOopMap getRegisterMap() { + return registerRefMap == null ? null : (HotSpotOopMap) registerRefMap.clone(); + } + + static MapEntry[] entries(HotSpotOopMap fixedMap) { + MapEntry[] result = new MapEntry[fixedMap.size()]; + for (int idx = 0; idx < fixedMap.size(); idx++) { + MapEntry dstType = MapEntry.getFromBits(idx, fixedMap); + result[idx] = dstType; + } + return result; + } + + private static boolean verifyUpdate(HotSpotOopMap dst, HotSpotOopMap src) { + return verifyUpdate(dst, src, true); + } + + private static boolean verifyUpdate(HotSpotOopMap dst, HotSpotOopMap src, boolean doAssert) { + for (int idx = 0; idx < Math.min(src.size(), dst.size()); idx++) { + if (!verifyUpdateEntry(idx, dst, src, doAssert)) { + return false; + } + } + return true; + } + + private static boolean verifyUpdateEntry(int idx, HotSpotOopMap dst, HotSpotOopMap src, boolean doAssert) { + MapEntry dstType = MapEntry.getFromBits(idx, dst); + MapEntry srcType = MapEntry.getFromBits(idx, src); + + if (dstType == MapEntry.Illegal || srcType == MapEntry.Illegal) { + assert !doAssert : String.format("Illegal RefMap bit pattern: %s (0b%s), %s (0b%s)", dstType, dstType.toBitString(), srcType, srcType.toBitString()); + return false; + } + switch (dstType) { + case NoReference: + return true; + case WideOop: + switch (srcType) { + case NoReference: + case WideOop: + return true; + default: + assert false : String.format("Illegal RefMap combination: %s (0b%s), %s (0b%s)", dstType, dstType.toBitString(), srcType, srcType.toBitString()); + return false; + } + case TwoNarrowOops: + case NarrowOopLowerHalf: + case NarrowOopUpperHalf: + switch (srcType) { + case TwoNarrowOops: + case NarrowOopLowerHalf: + case NarrowOopUpperHalf: + case NoReference: + return true; + default: + assert false : String.format("Illegal RefMap combination: %s (0b%s), %s (0b%s)", dstType, dstType.toBitString(), srcType, srcType.toBitString()); + return false; + } + default: + return false; + } + } + + @Override + public int hashCode() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof HotSpotReferenceMap) { + HotSpotReferenceMap that = (HotSpotReferenceMap) obj; + if (this.frameRefMap.equals(that.frameRefMap) && Objects.equals(this.registerRefMap, that.registerRefMap) && this.target.equals(that.target)) { + return true; + } + } + return false; + } + + @Override + public boolean hasRegisterRefMap() { + return registerRefMap != null && registerRefMap.size() > 0; + } + + @Override + public boolean hasFrameRefMap() { + return frameRefMap != null && frameRefMap.size() > 0; + } + + @Override + public void appendRegisterMap(StringBuilder sb, RefMapFormatter formatter) { + for (int idx = 0; idx < registerRefMap.size(); idx++) { + MapEntry dstType = MapEntry.getFromBits(idx, registerRefMap); + if (dstType != MapEntry.NoReference) { + sb.append(' ').append(formatter.formatRegister(idx)).append(':').append(dstType); + } + } + } + + @Override + public void appendFrameMap(StringBuilder sb, RefMapFormatter formatter) { + for (int idx = 0; idx < frameRefMap.size(); idx++) { + MapEntry dstType = MapEntry.getFromBits(idx, frameRefMap); + if (dstType != MapEntry.NoReference) { + sb.append(' ').append(formatter.formatStackSlot(idx)).append(':').append(dstType); + } + } + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + if (registerRefMap != null) { + sb.append("Registers = "); + sb.append(registerRefMap); + } + sb.append("Stack = "); + sb.append(frameRefMap); + return sb.toString(); + } + + public void verify() { + assert verifyUpdate(frameRefMap, frameRefMap); + assert registerRefMap == null || verifyUpdate(registerRefMap, registerRefMap); + } +}