Skip to content

Commit

Permalink
[GR-17176] TruffleStrings: remove JDK8-specific code.
Browse files Browse the repository at this point in the history
PullRequest: graal/11023
  • Loading branch information
djoooooe committed Feb 16, 2022
2 parents 07d5e60 + 4135da2 commit 40e0b96
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 132 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,6 @@
import static org.graalvm.compiler.replacements.ArrayIndexOf.strideAsPowerOf2;
import static org.graalvm.compiler.truffle.common.TruffleCompilerRuntime.getRuntime;

import java.lang.reflect.Type;

import org.graalvm.compiler.core.common.type.StampFactory;
import org.graalvm.compiler.debug.GraalError;
import org.graalvm.compiler.lir.amd64.AMD64CalcStringAttributesOp;
import org.graalvm.compiler.nodes.ConstantNode;
Expand All @@ -43,15 +40,9 @@
import org.graalvm.compiler.nodes.ValueNode;
import org.graalvm.compiler.nodes.calc.AddNode;
import org.graalvm.compiler.nodes.calc.LeftShiftNode;
import org.graalvm.compiler.nodes.calc.NarrowNode;
import org.graalvm.compiler.nodes.calc.ZeroExtendNode;
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
import org.graalvm.compiler.nodes.memory.OnHeapMemoryAccess;
import org.graalvm.compiler.nodes.memory.ReadNode;
import org.graalvm.compiler.nodes.memory.WriteNode;
import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
import org.graalvm.compiler.nodes.spi.Replacements;
import org.graalvm.compiler.phases.util.Providers;
import org.graalvm.compiler.replacements.ArrayIndexOfNode;
Expand Down Expand Up @@ -216,61 +207,6 @@ public static ValueNode toByteOffset(MetaAccessProvider metaAccess, GraphBuilder
return graph.add(AddNode.create(shifted, ConstantNode.forLong(metaAccess.getArrayBaseOffset(stride), graph.getGraph()), NodeView.DEFAULT));
}

private abstract static class TStringAccessPlugin extends InvocationPlugin {

final JavaKind stride;
final boolean isNative;

protected TStringAccessPlugin(JavaKind stride, boolean isNative, String name, Type... argumentTypes) {
super(name, argumentTypes);
this.stride = stride;
this.isNative = isNative;
}

ValueNode asChecked(GraphBuilderContext b, ValueNode array) {
return isNative ? array : b.nullCheckedValue(array);
}

LocationIdentity getLocationIdentity() {
return isNative ? NamedLocationIdentity.OFF_HEAP_LOCATION : getArrayLocation(JavaKind.Byte);
}
}

private static final class TStringReadPlugin extends TStringAccessPlugin {

private TStringReadPlugin(JavaKind stride, boolean isNative, String name, Type... argumentTypes) {
super(stride, isNative, name, argumentTypes);
}

@Override
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode array, ValueNode offset) {
OffsetAddressNode address = b.add(new OffsetAddressNode(asChecked(b, array), offset));
ReadNode read = b.add(new ReadNode(address, getLocationIdentity(), StampFactory.forInteger(stride.getBitCount()), OnHeapMemoryAccess.BarrierType.NONE));
if (S4.equals(stride)) {
b.push(stride, read);
} else {
ValueNode zeroExtend = b.add(ZeroExtendNode.create(read, stride.getBitCount(), JavaKind.Int.getBitCount(), NodeView.DEFAULT));
b.addPush(JavaKind.Int, zeroExtend);
}
return true;
}
}

private static final class TStringWritePlugin extends TStringAccessPlugin {

private TStringWritePlugin(JavaKind stride, boolean isNative, String name, Type... argumentTypes) {
super(stride, isNative, name, argumentTypes);
}

@Override
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode array, ValueNode offset, ValueNode value) {
OffsetAddressNode address = b.add(new OffsetAddressNode(asChecked(b, array), offset));
ValueNode narrowed = b.add(NarrowNode.create(value, stride.getBitCount(), NodeView.DEFAULT));
b.add(new WriteNode(address, getLocationIdentity(), narrowed, OnHeapMemoryAccess.BarrierType.NONE));
return true;
}
}

public static JavaKind constantStrideParam(ValueNode param) {
if (!param.isJavaConstant()) {
throw GraalError.shouldNotReachHere();
Expand Down Expand Up @@ -339,10 +275,6 @@ public static LocationIdentity inferLocationIdentity(ValueNode isNativeA, ValueN
private static void registerTStringPlugins(AMD64 architecture, InvocationPlugins plugins, MetaAccessProvider metaAccess, Replacements replacements) {
final ResolvedJavaType tStringOps = getRuntime().resolveType(metaAccess, "com.oracle.truffle.api.strings.TStringOps");
InvocationPlugins.Registration r = new InvocationPlugins.Registration(plugins, new InvocationPlugins.ResolvedJavaSymbol(tStringOps), replacements);
registerTStringReadPlugins(r, true);
registerTStringReadPlugins(r, false);
registerTStringWritePlugins(r, true);
registerTStringWritePlugins(r, false);

r.register(new InvocationPlugin("runIndexOfAny1", Node.class, Object.class, long.class, int.class, int.class, boolean.class, int.class, int.class) {
@Override
Expand Down Expand Up @@ -493,25 +425,4 @@ public static boolean applyIndexOf(GraphBuilderContext b, boolean findTwoConsecu
b.addPush(JavaKind.Int, new ArrayIndexOfNode(NONE, constStride, findTwoConsecutive, withMask, locationIdentity, array, offset, length, fromIndex, values));
return true;
}

private static void registerTStringReadPlugins(InvocationPlugins.Registration r, boolean isNative) {
String suffix = getSuffix(isNative);
Class<?> arrayAClass = isNative ? long.class : Object.class;
r.register(new TStringReadPlugin(S1, isNative, "runReadS0" + suffix, arrayAClass, long.class));
r.register(new TStringReadPlugin(S2, isNative, "runReadS1" + suffix, arrayAClass, long.class));
r.register(new TStringReadPlugin(S4, isNative, "runReadS2" + suffix, arrayAClass, long.class));
}

private static void registerTStringWritePlugins(InvocationPlugins.Registration r, boolean isNative) {
String suffix = getSuffix(isNative);
Class<?> arrayAClass = isNative ? long.class : byte[].class;
r.register(new TStringWritePlugin(S1, isNative, "runWriteS0" + suffix, arrayAClass, long.class, byte.class));
r.register(new TStringWritePlugin(S2, isNative, "runWriteS1" + suffix, arrayAClass, long.class, char.class));
r.register(new TStringWritePlugin(S4, isNative, "runWriteS2" + suffix, arrayAClass, long.class, int.class));
}

private static String getSuffix(boolean isNative) {
return isNative ? "Native" : "Managed";
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,8 @@ public final boolean isMutable() {
}

final boolean isCompatibleTo(int enc, int maxCompatibleCodeRange) {
return this.encoding() == enc || !DEBUG_STRICT_ENCODING_CHECKS && this instanceof TruffleString && ((TruffleString) this).codeRange() < maxCompatibleCodeRange;
// GR-31985: workaround: the binary OR avoids unnecessary loop unswitching on this check
return (this.encoding() == enc) | ((!DEBUG_STRICT_ENCODING_CHECKS && this instanceof TruffleString && ((TruffleString) this).codeRange() < maxCompatibleCodeRange));
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1480,54 +1480,29 @@ abstract static class CreateJavaStringNode extends Node {

abstract String execute(AbstractTruffleString a, Object arrayA);

@Specialization(guards = "isStride0(a)")
String latin1s0(AbstractTruffleString a, Object arrayA) {
assert isUTF16Compatible(a);
char[] chars = new char[a.length()];
for (int i = 0; i < a.length(); i++) {
chars[i] = (char) TStringOps.readS0(a, arrayA, i);
TStringConstants.truffleSafePointPoll(this, i + 1);
}
return createString(chars);
}

@Specialization(guards = "isStride1(a)")
String utf16S1(AbstractTruffleString a, Object arrayA) {
assert isUTF16Compatible(a);
// using the string constructor with byte array + charset would alter broken UTF-16
// strings (containing broken surrogate pairs or 0xFFFE), work around by converting the
// byte array to a char array
char[] chars = new char[a.length()];
for (int i = 0; i < a.length(); i++) {
chars[i] = TStringOps.readS1(a, arrayA, i);
TStringConstants.truffleSafePointPoll(this, i + 1);
}
return createString(chars);
}

@Specialization(guards = "isStride2(a)")
String utf16S2(AbstractTruffleString a, Object arrayA) {
@Specialization
String createJavaString(AbstractTruffleString a, Object arrayA,
@Cached ConditionProfile reuseProfile,
@Cached GetCodeRangeNode getCodeRangeNode,
@Cached RawArrayCopyBytesNode arrayCopyBytesNode) {
assert isUTF16Compatible(a);
// using the string constructor with byte array + charset would alter broken UTF-16
// strings (containing broken surrogate pairs or 0xFFFE), work around by converting the
// byte array to a char array
char[] chars = new char[a.length()];
for (int i = 0; i < a.length(); i++) {
chars[i] = (char) TStringOps.readS2(a, arrayA, i);
TStringConstants.truffleSafePointPoll(this, i + 1);
final int codeRange = getCodeRangeNode.execute(a);
final int stride = Stride.fromCodeRangeUTF16(codeRange);
final byte[] bytes;
if (reuseProfile.profile(a instanceof TruffleString && arrayA instanceof byte[] && a.length() << a.stride() == ((byte[]) arrayA).length && a.stride() == stride)) {
assert a.offset() == 0;
bytes = (byte[]) arrayA;
} else {
bytes = new byte[a.length() << stride];
arrayCopyBytesNode.execute(arrayA, a.offset(), a.stride(), bytes, 0, stride, a.length());
}
return createString(chars);
return TStringUnsafe.createJavaString(bytes, stride);
}

private static boolean isUTF16Compatible(AbstractTruffleString a) {
return a.isCompatibleTo(TruffleString.Encoding.UTF_16) ||
a instanceof MutableTruffleString && ((MutableTruffleString) a).codeRange() < TruffleString.Encoding.UTF_16.maxCompatibleCodeRange;
}

@TruffleBoundary
private static String createString(char[] chars) {
return new String(chars);
}
}

@ImportStatic(TStringGuards.class)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,21 +43,43 @@

import java.lang.reflect.Field;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;

import sun.misc.Unsafe;

final class TStringUnsafe {

@TruffleBoundary
private static int getJavaSpecificationVersion() {
String value = System.getProperty("java.specification.version");
if (value.startsWith("1.")) {
value = value.substring(2);
}
return Integer.parseInt(value);
}

/**
* The integer value corresponding to the value of the {@code java.specification.version} system
* property after any leading {@code "1."} has been stripped.
*/
static final int JAVA_SPEC = getJavaSpecificationVersion();

private static final sun.misc.Unsafe UNSAFE = getUnsafe();
private static final long javaStringValueFieldOffset;
private static final long javaStringCoderFieldOffset;
private static final long javaStringHashFieldOffset;

static {
if (JAVA_SPEC <= 8) {
throw new RuntimeException("TruffleString requires Java version > 8");
}
Field valueField = getStringDeclaredField("value");
javaStringValueFieldOffset = UNSAFE.objectFieldOffset(valueField);
Field coderField = getStringDeclaredField("coder");
Field hashField = getStringDeclaredField("hash");
javaStringValueFieldOffset = UNSAFE.objectFieldOffset(valueField);
javaStringCoderFieldOffset = UNSAFE.objectFieldOffset(coderField);
javaStringHashFieldOffset = UNSAFE.objectFieldOffset(hashField);
}

@TruffleBoundary
Expand Down Expand Up @@ -85,6 +107,7 @@ private static Unsafe getUnsafe() {
}

static byte[] getJavaStringArray(String str) {
assert JAVA_SPEC > 8;
Object value = UNSAFE.getObject(str, javaStringValueFieldOffset);
assert value instanceof byte[];
return (byte[]) value;
Expand All @@ -94,6 +117,38 @@ static int getJavaStringStride(String s) {
return UNSAFE.getByte(s, javaStringCoderFieldOffset);
}

@TruffleBoundary
private static String allocateJavaString() {
try {
return (String) UNSAFE.allocateInstance(String.class);
} catch (Throwable e) {
throw CompilerDirectives.shouldNotReachHere("Could not allocate java string");
}
}

@TruffleBoundary
static String createJavaString(byte[] bytes, int stride) {
if (stride < 0 || stride > 1) {
throw CompilerDirectives.shouldNotReachHere("stride must be 0 or 1!");
}
String ret = allocateJavaString();
UNSAFE.putInt(ret, javaStringHashFieldOffset, 0);
UNSAFE.putByte(ret, javaStringCoderFieldOffset, (byte) stride);
UNSAFE.putObjectVolatile(ret, javaStringValueFieldOffset, bytes);
assert checkUnsafeStringResult(bytes, stride, ret);
return ret;
}

@TruffleBoundary
private static boolean checkUnsafeStringResult(byte[] bytes, int stride, String ret) {
int length = bytes.length >> stride;
char[] chars = new char[length];
for (int i = 0; i < length; i++) {
chars[i] = (char) TStringOps.readFromByteArray(bytes, stride, i);
}
return new String(chars).equals(ret);
}

static byte getByteManaged(Object array, long byteOffset) {
return UNSAFE.getByte(array, byteOffset);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5091,12 +5091,16 @@ static String doUTF16(TruffleString a,
}
cur = a.next;
if (cur != null) {
while (cur != a && cur.encoding() != Encoding.UTF_16.id) {
while (cur != a && !cur.isCompatibleTo(Encoding.UTF_16)) {
cur = cur.next;
}
} else {
cur = a;
}
if (cur.isJavaString()) {
// java string was inserted in parallel
return (String) cur.data();
}
TruffleString s = toJavaStringNode.execute(cur, toIndexableNode.execute(cur, cur.data()));
a.cacheInsert(s);
return (String) s.data();
Expand Down

0 comments on commit 40e0b96

Please sign in to comment.