Skip to content

Commit c3a8400

Browse files
committed
[GR-37600] Use floating unsafe reads for DynamicObject array locations.
PullRequest: graal/11595
2 parents a496996 + 0dac456 commit c3a8400

File tree

7 files changed

+166
-51
lines changed

7 files changed

+166
-51
lines changed

compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/GuardedUnsafeLoadNode.java

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -26,6 +26,7 @@
2626

2727
import static org.graalvm.compiler.nodeinfo.InputType.Guard;
2828

29+
import org.graalvm.compiler.core.common.memory.MemoryOrderMode;
2930
import org.graalvm.compiler.graph.NodeClass;
3031
import org.graalvm.compiler.nodeinfo.NodeInfo;
3132
import org.graalvm.compiler.nodes.ValueNode;
@@ -44,6 +45,11 @@ public GuardedUnsafeLoadNode(ValueNode object, ValueNode offset, JavaKind access
4445
this.guard = (GuardingNode) guard;
4546
}
4647

48+
public GuardedUnsafeLoadNode(ValueNode object, ValueNode offset, JavaKind accessKind, LocationIdentity locationIdentity, ValueNode guard, boolean forceLocation, MemoryOrderMode memoryOrder) {
49+
super(TYPE, object, offset, accessKind, locationIdentity, forceLocation, memoryOrder);
50+
this.guard = (GuardingNode) guard;
51+
}
52+
4753
public GuardedUnsafeLoadNode(ValueNode object, ValueNode offset, JavaKind accessKind, LocationIdentity locationIdentity, ValueNode guard) {
4854
this(object, offset, accessKind, locationIdentity, guard, false);
4955
}
@@ -59,6 +65,14 @@ public void setGuard(GuardingNode guard) {
5965
this.guard = guard;
6066
}
6167

68+
@Override
69+
protected ValueNode cloneAsArrayAccess(ValueNode location, LocationIdentity identity, MemoryOrderMode memOrder) {
70+
// Only improve the location identity; do not attempt to canonicalize to a RawLoadNode
71+
// since doing so would lose the guard and prevent floating the read after lowering.
72+
assert !getLocationIdentity().equals(identity);
73+
return new GuardedUnsafeLoadNode(object(), offset(), accessKind(), identity, (ValueNode) getGuard(), isLocationForced(), memOrder);
74+
}
75+
6276
@NodeIntrinsic
6377
public static native Object guardedLoad(Object object, long offset, @ConstantNodeParameter JavaKind kind, @ConstantNodeParameter LocationIdentity locationIdentity, GuardingNode guard);
6478
}

compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/arraycopy/ArrayCopySnippets.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,7 @@ public static void arraycopyNativeExceptionSnippet(@NonNullParameter Object src,
289289

290290
/**
291291
* Inlines a loop that performs an {@linkplain BasicArrayCopyNode#isExact() exact}
292-
* element-by-element array copy. The explict loop allows subsequent phases to optimize the
292+
* element-by-element array copy. The explicit loop allows subsequent phases to optimize the
293293
* code.
294294
*/
295295
@SuppressWarnings("unused")

compiler/src/org.graalvm.compiler.truffle.compiler/src/org/graalvm/compiler/truffle/compiler/substitutions/TruffleGraphBuilderPlugins.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ public static void registerInvocationPlugins(InvocationPlugins plugins, boolean
147147
registerFrameWithoutBoxingPlugins(plugins, metaAccess, canDelayIntrinsification, providers.getConstantReflection(), types, primitiveBoxTypes);
148148
registerTruffleSafepointPlugins(plugins, metaAccess, canDelayIntrinsification);
149149
registerNodePlugins(plugins, metaAccess, canDelayIntrinsification, providers.getConstantReflection(), types);
150+
registerDynamicObjectPlugins(plugins, metaAccess, canDelayIntrinsification);
150151
}
151152

152153
private static void registerTruffleSafepointPlugins(InvocationPlugins plugins, MetaAccessProvider metaAccess, boolean canDelayIntrinsification) {
@@ -851,6 +852,13 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec
851852
});
852853
}
853854

855+
private static void registerDynamicObjectPlugins(InvocationPlugins plugins, MetaAccessProvider metaAccess, boolean canDelayIntrinsification) {
856+
TruffleCompilerRuntime rt = TruffleCompilerRuntime.getRuntime();
857+
ResolvedJavaType unsafeAccessType = rt.resolveType(metaAccess, "com.oracle.truffle.object.UnsafeAccess");
858+
Registration r = new Registration(plugins, new ResolvedJavaSymbol(unsafeAccessType));
859+
registerUnsafeLoadStorePlugins(r, canDelayIntrinsification, null, JavaKind.Long);
860+
}
861+
854862
public static void registerUnsafeCast(Registration r, boolean canDelayIntrinsification, EconomicSet<ResolvedJavaType> primitiveBoxTypes) {
855863
r.register(new RequiredInvocationPlugin("unsafeCast", Object.class, Class.class, boolean.class, boolean.class, boolean.class) {
856864
@Override

compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/GraalTruffleRuntime.java

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -421,12 +421,16 @@ private static UnmodifiableEconomicMap<String, Class<?>> initLookupTypes(Iterabl
421421
throw new NoClassDefFoundError(className);
422422
}
423423
}
424-
String className = "com.oracle.truffle.api.strings.TStringOps";
425-
try {
426-
Class<?> c = Class.forName(className);
427-
m.put(c.getName(), c);
428-
} catch (ClassNotFoundException e) {
429-
throw new NoClassDefFoundError(className);
424+
for (String className : new String[]{
425+
"com.oracle.truffle.api.strings.TStringOps",
426+
"com.oracle.truffle.object.UnsafeAccess",
427+
}) {
428+
try {
429+
Class<?> c = Class.forName(className);
430+
m.put(c.getName(), c);
431+
} catch (ClassNotFoundException e) {
432+
throw new NoClassDefFoundError(className);
433+
}
430434
}
431435
return m;
432436
}

truffle/src/com.oracle.truffle.object/src/com/oracle/truffle/object/CoreLocations.java

Lines changed: 31 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,12 @@
4141
package com.oracle.truffle.object;
4242

4343
import static com.oracle.truffle.object.LayoutImpl.ACCESS;
44+
import static com.oracle.truffle.object.UnsafeAccess.ARRAY_INT_BASE_OFFSET;
45+
import static com.oracle.truffle.object.UnsafeAccess.ARRAY_INT_INDEX_SCALE;
46+
import static com.oracle.truffle.object.UnsafeAccess.unsafeGetLong;
47+
import static com.oracle.truffle.object.UnsafeAccess.unsafeGetObject;
48+
import static com.oracle.truffle.object.UnsafeAccess.unsafePutLong;
49+
import static com.oracle.truffle.object.UnsafeAccess.unsafePutObject;
4450

4551
import java.lang.reflect.Field;
4652
import java.util.Objects;
@@ -53,8 +59,6 @@
5359
import com.oracle.truffle.api.object.Property;
5460
import com.oracle.truffle.api.object.Shape;
5561

56-
import sun.misc.Unsafe;
57-
5862
/**
5963
* Property location.
6064
*
@@ -490,10 +494,7 @@ public final void accept(LocationVisitor locationVisitor) {
490494
}
491495

492496
static class LongArrayLocation extends ArrayLocation implements LongLocation {
493-
private static final Unsafe UNSAFE = getUnsafe();
494497
private static final int ALIGN = LONG_ARRAY_SLOT_SIZE - 1;
495-
private static final long ARRAY_INT_BASE_OFFSET = UNSAFE.arrayBaseOffset(int[].class);
496-
private static final long ARRAY_INT_INDEX_SCALE = UNSAFE.arrayIndexScale(int[].class);
497498

498499
protected final boolean allowInt;
499500

@@ -535,13 +536,30 @@ protected static final int[] getArray(DynamicObject store) {
535536
@Override
536537
public long getLong(DynamicObject store, boolean guard) {
537538
int[] array = getArray(store);
538-
return UNSAFE.getLong(array, getOffset(array));
539+
int idx = index;
540+
boolean boundsCheck = idx >= 0 && idx < array.length - ALIGN;
541+
if (boundsCheck) {
542+
long offset = ARRAY_INT_BASE_OFFSET + ARRAY_INT_INDEX_SCALE * idx;
543+
return unsafeGetLong(array, offset, boundsCheck, null);
544+
} else {
545+
throw arrayIndexOutOfBounds(idx);
546+
}
539547
}
540548

541549
public final void setLongInternal(DynamicObject store, long value) {
542550
int[] array = getArray(store);
543-
long offset = getOffset(array);
544-
UNSAFE.putLong(array, offset, value);
551+
int idx = index;
552+
if (idx >= 0 && idx < array.length - ALIGN) {
553+
long offset = ARRAY_INT_BASE_OFFSET + ARRAY_INT_INDEX_SCALE * idx;
554+
unsafePutLong(array, offset, value, null);
555+
} else {
556+
throw arrayIndexOutOfBounds(idx);
557+
}
558+
}
559+
560+
private static ArrayIndexOutOfBoundsException arrayIndexOutOfBounds(int idx) {
561+
CompilerDirectives.transferToInterpreterAndInvalidate();
562+
throw new ArrayIndexOutOfBoundsException(idx);
545563
}
546564

547565
@Override
@@ -578,15 +596,6 @@ public boolean equals(Object obj) {
578596
public boolean isImplicitCastIntToLong() {
579597
return allowInt;
580598
}
581-
582-
protected final long getOffset(int[] array) {
583-
int idx = index;
584-
if (idx < 0 || idx >= array.length - ALIGN) {
585-
CompilerDirectives.transferToInterpreterAndInvalidate();
586-
throw new ArrayIndexOutOfBoundsException(idx);
587-
}
588-
return ARRAY_INT_BASE_OFFSET + ARRAY_INT_INDEX_SCALE * idx;
589-
}
590599
}
591600

592601
public static LongLocation createLongLocation(LongLocation longLocation, boolean allowInt) {
@@ -941,7 +950,6 @@ static int upperInt(long value) {
941950
static final class DynamicObjectFieldLocation extends SimpleObjectFieldLocation {
942951
private final long offset;
943952
private final Class<? extends DynamicObject> tclass;
944-
private static final Unsafe UNSAFE = getUnsafe();
945953

946954
private DynamicObjectFieldLocation(int index, long offset, Class<? extends DynamicObject> declaringClass) {
947955
super(index);
@@ -950,20 +958,20 @@ private DynamicObjectFieldLocation(int index, long offset, Class<? extends Dynam
950958
}
951959

952960
DynamicObjectFieldLocation(int index, Field objectField) {
953-
this(index, UNSAFE.objectFieldOffset(objectField), objectField.getDeclaringClass().asSubclass(DynamicObject.class));
961+
this(index, UnsafeAccess.objectFieldOffset(objectField), objectField.getDeclaringClass().asSubclass(DynamicObject.class));
954962
if (objectField.getType() != Object.class) {
955963
throw new IllegalArgumentException();
956964
}
957965
}
958966

959967
@Override
960968
public Object get(DynamicObject store, boolean guard) {
961-
return UNSAFE.getObject(receiverCast(store, tclass), offset);
969+
return unsafeGetObject(receiverCast(store, tclass), offset);
962970
}
963971

964972
@Override
965973
public void set(DynamicObject store, Object value, boolean guard, boolean init) {
966-
UNSAFE.putObject(receiverCast(store, tclass), offset, value);
974+
unsafePutObject(receiverCast(store, tclass), offset, value);
967975
}
968976

969977
@Override
@@ -978,8 +986,6 @@ static final class DynamicLongFieldLocation extends SimpleLongFieldLocation {
978986
/** {@link DynamicObject} subclass holding field. */
979987
private final Class<? extends DynamicObject> tclass;
980988

981-
private static final Unsafe UNSAFE = getUnsafe();
982-
983989
DynamicLongFieldLocation(int index, long offset, Class<? extends DynamicObject> declaringClass) {
984990
super(index);
985991
this.offset = offset;
@@ -989,12 +995,12 @@ static final class DynamicLongFieldLocation extends SimpleLongFieldLocation {
989995

990996
@Override
991997
public long getLong(DynamicObject store, boolean guard) {
992-
return UNSAFE.getLong(receiverCast(store, tclass), offset);
998+
return unsafeGetLong(receiverCast(store, tclass), offset);
993999
}
9941000

9951001
@Override
9961002
public void setLong(DynamicObject store, long value, boolean guard, boolean init) {
997-
UNSAFE.putLong(receiverCast(store, tclass), offset, value);
1003+
unsafePutLong(receiverCast(store, tclass), offset, value);
9981004
}
9991005

10001006
@Override
@@ -1014,18 +1020,4 @@ static int getLocationOrdinal(CoreLocation loc) {
10141020
throw new IllegalArgumentException(internal.getClass().getName());
10151021
}
10161022
}
1017-
1018-
static Unsafe getUnsafe() {
1019-
try {
1020-
return Unsafe.getUnsafe();
1021-
} catch (SecurityException e) {
1022-
}
1023-
try {
1024-
Field theUnsafeInstance = Unsafe.class.getDeclaredField("theUnsafe");
1025-
theUnsafeInstance.setAccessible(true);
1026-
return (Unsafe) theUnsafeInstance.get(Unsafe.class);
1027-
} catch (Exception e) {
1028-
throw new RuntimeException("exception while trying to get Unsafe.theUnsafe via reflection:", e);
1029-
}
1030-
}
10311023
}

truffle/src/com.oracle.truffle.object/src/com/oracle/truffle/object/DefaultLayout.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,6 @@
6161
import com.oracle.truffle.object.CoreLocations.LongLocation;
6262
import com.oracle.truffle.object.CoreLocations.ObjectLocation;
6363

64-
import sun.misc.Unsafe;
65-
6664
@SuppressWarnings("deprecation")
6765
class DefaultLayout extends LayoutImpl {
6866
private final ObjectLocation[] objectFields;
@@ -210,7 +208,6 @@ private static final class LayoutInfo {
210208
final LongLocation[] primitiveFields;
211209

212210
private static final ConcurrentMap<Class<? extends DynamicObject>, LayoutInfo> LAYOUT_INFO_MAP = new ConcurrentHashMap<>();
213-
private static final Unsafe UNSAFE = CoreLocations.getUnsafe();
214211

215212
static LayoutInfo getOrCreateLayoutInfo(Class<? extends DynamicObject> dynamicObjectClass) {
216213
LayoutInfo layoutInfo = LAYOUT_INFO_MAP.get(dynamicObjectClass);
@@ -279,7 +276,7 @@ private static Class<? extends DynamicObject> collectFields(Class<? extends Dyna
279276
if (field.getType() == Object.class) {
280277
objectFieldList.add(new CoreLocations.DynamicObjectFieldLocation(objectFieldList.size(), field));
281278
} else if (field.getType() == long.class) {
282-
long offset = UNSAFE.objectFieldOffset(field);
279+
long offset = UnsafeAccess.objectFieldOffset(field);
283280
if (offset % Long.BYTES == 0) {
284281
primitiveFieldList.add(new CoreLocations.DynamicLongFieldLocation(primitiveFieldList.size(), offset, clazz));
285282
}
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/*
2+
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* The Universal Permissive License (UPL), Version 1.0
6+
*
7+
* Subject to the condition set forth below, permission is hereby granted to any
8+
* person obtaining a copy of this software, associated documentation and/or
9+
* data (collectively the "Software"), free of charge and under any and all
10+
* copyright rights in the Software, and any and all patent rights owned or
11+
* freely licensable by each licensor hereunder covering either (i) the
12+
* unmodified Software as contributed to or provided by such licensor, or (ii)
13+
* the Larger Works (as defined below), to deal in both
14+
*
15+
* (a) the Software, and
16+
*
17+
* (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
18+
* one is included with the Software each a "Larger Work" to which the Software
19+
* is contributed by such licensors),
20+
*
21+
* without restriction, including without limitation the rights to copy, create
22+
* derivative works of, display, perform, and distribute the Software and make,
23+
* use, sell, offer for sale, import, export, have made, and have sold the
24+
* Software and the Larger Work(s), and to sublicense the foregoing rights on
25+
* either these or other terms.
26+
*
27+
* This license is subject to the following condition:
28+
*
29+
* The above copyright notice and either this complete permission notice or at a
30+
* minimum a reference to the UPL must be included in all copies or substantial
31+
* portions of the Software.
32+
*
33+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39+
* SOFTWARE.
40+
*/
41+
package com.oracle.truffle.object;
42+
43+
import java.lang.reflect.Field;
44+
45+
import sun.misc.Unsafe;
46+
47+
final class UnsafeAccess {
48+
49+
private static final Unsafe UNSAFE = getUnsafe();
50+
51+
static final long ARRAY_INT_BASE_OFFSET = UNSAFE.arrayBaseOffset(int[].class);
52+
static final long ARRAY_INT_INDEX_SCALE = UNSAFE.arrayIndexScale(int[].class);
53+
54+
static long objectFieldOffset(Field field) {
55+
return UNSAFE.objectFieldOffset(field);
56+
}
57+
58+
static Object unsafeGetObject(Object receiver, long offset) {
59+
return UNSAFE.getObject(receiver, offset);
60+
}
61+
62+
static void unsafePutObject(Object receiver, long offset, Object value) {
63+
UNSAFE.putObject(receiver, offset, value);
64+
}
65+
66+
static long unsafeGetLong(Object receiver, long offset) {
67+
return UNSAFE.getLong(receiver, offset);
68+
}
69+
70+
static void unsafePutLong(Object receiver, long offset, long value) {
71+
UNSAFE.putLong(receiver, offset, value);
72+
}
73+
74+
@SuppressWarnings("unused")
75+
static long unsafeGetLong(Object receiver, long offset, boolean condition, Object locationIdentity) {
76+
return UNSAFE.getLong(receiver, offset);
77+
}
78+
79+
@SuppressWarnings("unused")
80+
static void unsafePutLong(Object receiver, long offset, long value, Object locationIdentity) {
81+
UNSAFE.putLong(receiver, offset, value);
82+
}
83+
84+
private UnsafeAccess() {
85+
}
86+
87+
private static Unsafe getUnsafe() {
88+
try {
89+
return Unsafe.getUnsafe();
90+
} catch (SecurityException e) {
91+
}
92+
try {
93+
Field theUnsafeInstance = Unsafe.class.getDeclaredField("theUnsafe");
94+
theUnsafeInstance.setAccessible(true);
95+
return (Unsafe) theUnsafeInstance.get(Unsafe.class);
96+
} catch (Exception e) {
97+
throw new RuntimeException("exception while trying to get Unsafe.theUnsafe via reflection:", e);
98+
}
99+
}
100+
}

0 commit comments

Comments
 (0)