Skip to content

Commit e5cab6b

Browse files
author
Flavio Brasil
committed
virtualize unsafe compare and swap calls
1 parent d8bf902 commit e5cab6b

File tree

2 files changed

+170
-1
lines changed

2 files changed

+170
-1
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
/*
2+
* Copyright (c) 2011, 2016, 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. Oracle designates this
8+
* particular file as subject to the "Classpath" exception as provided
9+
* by Oracle in the LICENSE file that accompanied this code.
10+
*
11+
* This code is distributed in the hope that it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+
* version 2 for more details (a copy is included in the LICENSE file that
15+
* accompanied this code).
16+
*
17+
* You should have received a copy of the GNU General Public License version
18+
* 2 along with this work; if not, write to the Free Software Foundation,
19+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+
*
21+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+
* or visit www.oracle.com if you need additional information or have any
23+
* questions.
24+
*/
25+
package org.graalvm.compiler.core.test.ea;
26+
27+
import java.util.concurrent.atomic.AtomicReference;
28+
29+
import org.graalvm.compiler.nodes.java.LogicCompareAndSwapNode;
30+
import org.junit.Test;
31+
32+
import jdk.vm.ci.meta.JavaConstant;
33+
34+
public class UnsafeCompareAndSwapVirtualizationTest extends EATestBase {
35+
36+
private static Object obj1 = new Object();
37+
private static Object obj2 = new Object();
38+
39+
public static boolean bothVirtualNoMatch() {
40+
AtomicReference<Object> a = new AtomicReference<>();
41+
return a.compareAndSet(new Object(), new Object());
42+
}
43+
44+
@Test
45+
public void bothVirtualNoMatchTest() {
46+
testEscapeAnalysis("bothVirtualNoMatch", JavaConstant.INT_0, true);
47+
assertTrue(graph.getNodes(LogicCompareAndSwapNode.TYPE).isEmpty());
48+
}
49+
50+
public static boolean bothVirtualMatch() {
51+
Object expect = new Object();
52+
AtomicReference<Object> a = new AtomicReference<>(expect);
53+
return a.compareAndSet(expect, new Object());
54+
}
55+
56+
@Test
57+
public void bothVirtualMatchTest() {
58+
testEscapeAnalysis("bothVirtualMatch", JavaConstant.INT_1, true);
59+
assertTrue(graph.getNodes(LogicCompareAndSwapNode.TYPE).isEmpty());
60+
}
61+
62+
public static boolean expectedVirtualMatch() {
63+
Object o = new Object();
64+
AtomicReference<Object> a = new AtomicReference<>(o);
65+
return a.compareAndSet(o, obj1);
66+
}
67+
68+
@Test
69+
public void expectedVirtualMatchTest() {
70+
testEscapeAnalysis("expectedVirtualMatch", null, true);
71+
assertTrue(graph.getNodes(LogicCompareAndSwapNode.TYPE).isEmpty());
72+
}
73+
74+
public static boolean expectedVirtualNoMatch() {
75+
Object o = new Object();
76+
AtomicReference<Object> a = new AtomicReference<>();
77+
return a.compareAndSet(o, obj1);
78+
}
79+
80+
@Test
81+
public void expectedVirtualNoMatchTest() {
82+
testEscapeAnalysis("expectedVirtualNoMatch", null, true);
83+
assertTrue(graph.getNodes(LogicCompareAndSwapNode.TYPE).isEmpty());
84+
}
85+
86+
public static boolean bothNonVirtualNoMatch() {
87+
AtomicReference<Object> a = new AtomicReference<>();
88+
return a.compareAndSet(obj1, obj2);
89+
}
90+
91+
@Test
92+
public void bothNonVirtualNoMatchTest() {
93+
testEscapeAnalysis("bothNonVirtualNoMatch", null, true);
94+
assertTrue(graph.getNodes(LogicCompareAndSwapNode.TYPE).isEmpty());
95+
}
96+
97+
public static boolean bothNonVirtualMatch() {
98+
AtomicReference<Object> a = new AtomicReference<>(obj1);
99+
return a.compareAndSet(obj1, obj2);
100+
}
101+
102+
@Test
103+
public void bothNonVirtualMatchTest() {
104+
testEscapeAnalysis("bothNonVirtualMatch", null, true);
105+
assertTrue(graph.getNodes(LogicCompareAndSwapNode.TYPE).isEmpty());
106+
}
107+
108+
public static boolean onlyInitialValueVirtualMatch() {
109+
AtomicReference<Object> a = new AtomicReference<>(new Object());
110+
return a.compareAndSet(obj1, obj2);
111+
}
112+
}

compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/UnsafeCompareAndSwapNode.java

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
*/
2525
package org.graalvm.compiler.nodes.java;
2626

27+
import static org.graalvm.compiler.core.common.calc.CanonicalCondition.EQ;
2728
import static org.graalvm.compiler.nodeinfo.InputType.Memory;
2829
import static org.graalvm.compiler.nodeinfo.InputType.Value;
2930
import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8;
@@ -32,22 +33,32 @@
3233
import org.graalvm.compiler.core.common.type.StampFactory;
3334
import org.graalvm.compiler.graph.NodeClass;
3435
import org.graalvm.compiler.nodeinfo.NodeInfo;
36+
import org.graalvm.compiler.nodes.ConstantNode;
37+
import org.graalvm.compiler.nodes.LogicConstantNode;
38+
import org.graalvm.compiler.nodes.LogicNode;
3539
import org.graalvm.compiler.nodes.NodeView;
3640
import org.graalvm.compiler.nodes.ValueNode;
41+
import org.graalvm.compiler.nodes.calc.CompareNode;
42+
import org.graalvm.compiler.nodes.calc.ConditionalNode;
3743
import org.graalvm.compiler.nodes.memory.AbstractMemoryCheckpoint;
3844
import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
3945
import org.graalvm.compiler.nodes.spi.Lowerable;
4046
import org.graalvm.compiler.nodes.spi.LoweringTool;
47+
import org.graalvm.compiler.nodes.spi.Virtualizable;
48+
import org.graalvm.compiler.nodes.spi.VirtualizerTool;
49+
import org.graalvm.compiler.nodes.virtual.VirtualInstanceNode;
50+
import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
4151
import org.graalvm.word.LocationIdentity;
4252

4353
import jdk.vm.ci.meta.JavaKind;
54+
import jdk.vm.ci.meta.ResolvedJavaField;
4455

4556
/**
4657
* Represents an atomic compare-and-swap operation. The result is a boolean that contains whether
4758
* the value matched the expected value.
4859
*/
4960
@NodeInfo(allowedUsageTypes = {Value, Memory}, cycles = CYCLES_8, size = SIZE_8)
50-
public final class UnsafeCompareAndSwapNode extends AbstractMemoryCheckpoint implements Lowerable, MemoryCheckpoint.Single {
61+
public final class UnsafeCompareAndSwapNode extends AbstractMemoryCheckpoint implements Lowerable, MemoryCheckpoint.Single, Virtualizable {
5162

5263
public static final NodeClass<UnsafeCompareAndSwapNode> TYPE = NodeClass.create(UnsafeCompareAndSwapNode.class);
5364
@Input ValueNode object;
@@ -98,4 +109,50 @@ public LocationIdentity getLocationIdentity() {
98109
public void lower(LoweringTool tool) {
99110
tool.getLowerer().lower(this, tool);
100111
}
112+
113+
@Override
114+
public void virtualize(VirtualizerTool tool) {
115+
ValueNode alias = tool.getAlias(object);
116+
if (alias instanceof VirtualInstanceNode && offset.isConstant()) {
117+
118+
VirtualInstanceNode obj = (VirtualInstanceNode) alias;
119+
120+
int index = resolveFieldIndex(obj);
121+
122+
if (index >= 0) {
123+
124+
ValueNode currentValue = tool.getEntry(obj, index);
125+
ValueNode expectedAlias = tool.getAlias(this.expected);
126+
ValueNode newValueAlias = tool.getAlias(this.newValue);
127+
128+
LogicNode equalsNode = CompareNode.createCompareNode(EQ, expectedAlias, currentValue, tool.getConstantReflectionProvider(), NodeView.DEFAULT);
129+
if (equalsNode instanceof LogicConstantNode) {
130+
131+
boolean equals = ((LogicConstantNode) equalsNode).getValue();
132+
if (equals) {
133+
tool.setVirtualEntry(obj, index, newValueAlias);
134+
}
135+
tool.replaceWith(ConstantNode.forBoolean(equals));
136+
137+
} else if (!(currentValue instanceof VirtualInstanceNode) &&
138+
!(expectedAlias instanceof VirtualObjectNode) &&
139+
!(newValueAlias instanceof VirtualObjectNode)) {
140+
ValueNode fieldValue = ConditionalNode.create(equalsNode, newValueAlias, currentValue, NodeView.DEFAULT);
141+
ValueNode result = ConditionalNode.create(equalsNode, ConstantNode.forBoolean(true), ConstantNode.forBoolean(false), NodeView.DEFAULT);
142+
143+
tool.setVirtualEntry(obj, index, fieldValue);
144+
tool.addNode(equalsNode);
145+
tool.addNode(fieldValue);
146+
tool.addNode(result);
147+
tool.replaceWith(result);
148+
}
149+
}
150+
}
151+
}
152+
153+
private int resolveFieldIndex(VirtualInstanceNode obj) {
154+
long fieldOffset = offset.asJavaConstant().asLong();
155+
ResolvedJavaField field = obj.type().findInstanceFieldWithOffset(fieldOffset, expected.getStackKind());
156+
return obj.fieldIndex(field);
157+
}
101158
}

0 commit comments

Comments
 (0)