Skip to content

Commit 3540dd4

Browse files
committedAug 28, 2020
8229897: [lworld] C1 should avoid allocation when reading a field from a flattened field
Reviewed-by: thartmann
1 parent 54b5410 commit 3540dd4

File tree

7 files changed

+1296
-32
lines changed

7 files changed

+1296
-32
lines changed
 

‎src/hotspot/share/c1/c1_GraphBuilder.cpp

+63-32
Original file line numberDiff line numberDiff line change
@@ -1837,25 +1837,27 @@ void GraphBuilder::access_field(Bytecodes::Code code) {
18371837
assert(Interpreter::bytecode_should_reexecute(code), "should reexecute");
18381838
state_before = copy_state_before();
18391839
}
1840-
obj = apop();
1841-
ObjectType* obj_type = obj->type()->as_ObjectType();
1842-
if (field->is_constant() && !field->is_flattened() && obj_type->is_constant() && !PatchALot) {
1843-
ciObject* const_oop = obj_type->constant_value();
1844-
if (!const_oop->is_null_object() && const_oop->is_loaded()) {
1845-
ciConstant field_value = field->constant_value_of(const_oop);
1846-
if (field_value.is_valid()) {
1847-
if (field->signature()->is_Q_signature() && field_value.is_null_or_zero()) {
1848-
// Non-flattened inline type field. Replace null by the default value.
1849-
constant = new Constant(new InstanceConstant(field->type()->as_inline_klass()->default_instance()));
1850-
} else {
1851-
constant = make_constant(field_value, field);
1852-
}
1853-
// For CallSite objects add a dependency for invalidation of the optimization.
1854-
if (field->is_call_site_target()) {
1855-
ciCallSite* call_site = const_oop->as_call_site();
1856-
if (!call_site->is_fully_initialized_constant_call_site()) {
1857-
ciMethodHandle* target = field_value.as_object()->as_method_handle();
1858-
dependency_recorder()->assert_call_site_target_value(call_site, target);
1840+
if (!has_delayed_flattened_field_access()) {
1841+
obj = apop();
1842+
ObjectType* obj_type = obj->type()->as_ObjectType();
1843+
if (field->is_constant() && !field->is_flattened() && obj_type->is_constant() && !PatchALot) {
1844+
ciObject* const_oop = obj_type->constant_value();
1845+
if (!const_oop->is_null_object() && const_oop->is_loaded()) {
1846+
ciConstant field_value = field->constant_value_of(const_oop);
1847+
if (field_value.is_valid()) {
1848+
if (field->signature()->is_Q_signature() && field_value.is_null_or_zero()) {
1849+
// Non-flattened inline type field. Replace null by the default value.
1850+
constant = new Constant(new InstanceConstant(field->type()->as_inline_klass()->default_instance()));
1851+
} else {
1852+
constant = make_constant(field_value, field);
1853+
}
1854+
// For CallSite objects add a dependency for invalidation of the optimization.
1855+
if (field->is_call_site_target()) {
1856+
ciCallSite* call_site = const_oop->as_call_site();
1857+
if (!call_site->is_fully_initialized_constant_call_site()) {
1858+
ciMethodHandle* target = field_value.as_object()->as_method_handle();
1859+
dependency_recorder()->assert_call_site_target_value(call_site, target);
1860+
}
18591861
}
18601862
}
18611863
}
@@ -1868,7 +1870,15 @@ void GraphBuilder::access_field(Bytecodes::Code code) {
18681870
state_before = copy_state_for_exception();
18691871
}
18701872
if (!field->is_flattened()) {
1871-
LoadField* load = new LoadField(obj, offset, field, false, state_before, needs_patching);
1873+
LoadField* load;
1874+
if (!has_delayed_flattened_field_access()) {
1875+
load = new LoadField(obj, offset, field, false, state_before, needs_patching);
1876+
} else {
1877+
load = new LoadField(_delayed_flattened_field_access->obj(),
1878+
_delayed_flattened_field_access->offset() + offset - field->holder()->as_inline_klass()->first_field_offset(),
1879+
field, false, state_before, needs_patching);
1880+
_delayed_flattened_field_access = NULL;
1881+
}
18721882
Value replacement = !needs_patching ? _memory->load(load) : load;
18731883
if (replacement != load) {
18741884
assert(replacement->is_linked() || !replacement->can_be_linked(), "should already by linked");
@@ -1893,18 +1903,38 @@ void GraphBuilder::access_field(Bytecodes::Code code) {
18931903
} else {
18941904
push(type, append(load));
18951905
}
1896-
} else { // flattened field, not optimized solution: re-instantiate the flattened value
1897-
assert(field->type()->is_inlinetype(), "Sanity check");
1898-
ciInlineKlass* inline_klass = field->type()->as_inline_klass();
1899-
int flattening_offset = field->offset() - inline_klass->first_field_offset();
1900-
assert(field->type()->is_inlinetype(), "Sanity check");
1901-
scope()->set_wrote_final();
1902-
scope()->set_wrote_fields();
1903-
NewInlineTypeInstance* new_instance = new NewInlineTypeInstance(inline_klass, state_before, false);
1904-
_memory->new_instance(new_instance);
1905-
apush(append_split(new_instance));
1906-
copy_inline_content(inline_klass, obj, field->offset(), new_instance, inline_klass->first_field_offset(),
1907-
state_before, needs_patching);
1906+
} else {
1907+
ciBytecodeStream s(method());
1908+
s.force_bci(bci());
1909+
s.next();
1910+
if (s.cur_bc() == Bytecodes::_getfield && !needs_patching) {
1911+
if (!has_delayed_flattened_field_access()) {
1912+
null_check(obj);
1913+
DelayedFlattenedFieldAccess* dffa = new DelayedFlattenedFieldAccess(obj, field, field->offset());
1914+
_delayed_flattened_field_access = dffa;
1915+
} else {
1916+
_delayed_flattened_field_access->update(field, offset - field->holder()->as_inline_klass()->first_field_offset());
1917+
}
1918+
} else {
1919+
assert(field->type()->is_inlinetype(), "Sanity check");
1920+
ciInlineKlass* inline_klass = field->type()->as_inline_klass();
1921+
assert(field->type()->is_inlinetype(), "Sanity check");
1922+
scope()->set_wrote_final();
1923+
scope()->set_wrote_fields();
1924+
NewInlineTypeInstance* new_instance = new NewInlineTypeInstance(inline_klass, state_before, false);
1925+
_memory->new_instance(new_instance);
1926+
apush(append_split(new_instance));
1927+
if (!has_delayed_flattened_field_access()) {
1928+
copy_inline_content(inline_klass, obj, field->offset(), new_instance, inline_klass->first_field_offset(),
1929+
state_before, needs_patching);
1930+
} else {
1931+
copy_inline_content(inline_klass, _delayed_flattened_field_access->obj(),
1932+
_delayed_flattened_field_access->offset() + field->offset() - field->holder()->as_inline_klass()->first_field_offset(),
1933+
new_instance, inline_klass->first_field_offset(),
1934+
state_before, needs_patching);
1935+
_delayed_flattened_field_access = NULL;
1936+
}
1937+
}
19081938
}
19091939
}
19101940
break;
@@ -3491,6 +3521,7 @@ GraphBuilder::GraphBuilder(Compilation* compilation, IRScope* scope)
34913521
, _inline_bailout_msg(NULL)
34923522
, _instruction_count(0)
34933523
, _osr_entry(NULL)
3524+
, _delayed_flattened_field_access(NULL)
34943525
{
34953526
int osr_bci = compilation->osr_bci();
34963527

‎src/hotspot/share/c1/c1_GraphBuilder.hpp

+24
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,26 @@
3535

3636
class MemoryBuffer;
3737

38+
class DelayedFlattenedFieldAccess : public CompilationResourceObj {
39+
private:
40+
Value _obj;
41+
ciField* _field;
42+
int _offset;
43+
public:
44+
DelayedFlattenedFieldAccess(Value obj, ciField* field, int offset)
45+
: _obj(obj)
46+
, _field(field)
47+
, _offset(offset) { }
48+
49+
void update(ciField* field, int offset) {
50+
_field = field;
51+
_offset += offset;
52+
}
53+
Value obj() { return _obj; }
54+
ciField* field() { return _field; }
55+
int offset() { return _offset; }
56+
};
57+
3858
class GraphBuilder {
3959
private:
4060
// Per-scope data. These are pushed and popped as we descend into
@@ -191,6 +211,10 @@ class GraphBuilder {
191211
Instruction* _last; // the last instruction added
192212
bool _skip_block; // skip processing of the rest of this block
193213

214+
DelayedFlattenedFieldAccess* _delayed_flattened_field_access;
215+
bool has_delayed_flattened_field_access() { return _delayed_flattened_field_access != NULL; }
216+
217+
194218
// accessors
195219
ScopeData* scope_data() const { return _scope_data; }
196220
Compilation* compilation() const { return _compilation; }

‎test/hotspot/jtreg/compiler/valhalla/inlinetypes/GetfieldChains.jcod

+926
Large diffs are not rendered by default.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* Copyright (c) 2020, 2020, 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+
24+
package compiler.valhalla.inlinetypes;
25+
26+
public class NamedRectangle {
27+
Rectangle rect = new Rectangle();
28+
String name = "";
29+
30+
static int getP1X(NamedRectangle nr) {
31+
return nr.rect
32+
.p1
33+
.x;
34+
}
35+
36+
static Point getP1(NamedRectangle nr) {
37+
return nr.rect
38+
.p1;
39+
}
40+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
* Copyright (c) 2020, 2020, 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+
24+
package compiler.valhalla.inlinetypes;
25+
26+
public inline class Point {
27+
int x = 4;
28+
int y = 7;
29+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
* Copyright (c) 2020, 2020, 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+
24+
package compiler.valhalla.inlinetypes;
25+
26+
public inline class Rectangle {
27+
Point p0 = new Point();
28+
Point p1 = new Point();
29+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
/*
2+
* Copyright (c) 2020, 2020, 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+
24+
25+
package compiler.valhalla.inlinetypes;
26+
27+
import java.lang.invoke.*;
28+
import java.lang.reflect.Method;
29+
import java.nio.file.NoSuchFileException;
30+
import java.util.Arrays;
31+
32+
import jdk.experimental.value.MethodHandleBuilder;
33+
import jdk.test.lib.Asserts;
34+
35+
/*
36+
* @test
37+
* @key randomness
38+
* @summary Verify that chains of getfields on flattened fields are correctly optimized
39+
* @modules java.base/jdk.experimental.value
40+
* @library /testlibrary /test/lib /compiler/whitebox /
41+
* @requires os.simpleArch == "x64"
42+
* @compile TestGetfieldChains.java NamedRectangle.java Rectangle.java Point.java GetfieldChains.jcod
43+
* @run driver ClassFileInstaller sun.hotspot.WhiteBox jdk.test.lib.Platform
44+
* @run main/othervm/timeout=300 -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions
45+
* -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI
46+
* compiler.valhalla.inlinetypes.InlineTypeTest
47+
* compiler.valhalla.inlinetypes.TestGetfieldChains
48+
*/
49+
50+
public class TestGetfieldChains extends InlineTypeTest {
51+
public static final int C1 = COMP_LEVEL_SIMPLE;
52+
public static final int C2 = COMP_LEVEL_FULL_OPTIMIZATION;
53+
54+
public static void main(String[] args) throws Throwable {
55+
TestGetfieldChains test = new TestGetfieldChains();
56+
test.run(args, TestGetfieldChains.class);
57+
}
58+
59+
@Override
60+
public int getNumScenarios() {
61+
return 5;
62+
}
63+
64+
@Override
65+
public String[] getVMParameters(int scenario) {
66+
switch (scenario) {
67+
case 0: return new String[] { // C1 only
68+
"-XX:TieredStopAtLevel=1",
69+
"-XX:+TieredCompilation",
70+
};
71+
case 1: return new String[] { // C2 only. (Make sure the tests are correctly written)
72+
"-XX:TieredStopAtLevel=4",
73+
"-XX:-TieredCompilation",
74+
"-XX:-OmitStackTraceInFastThrow",
75+
};
76+
case 2: return new String[] { // interpreter only
77+
"-Xint",
78+
};
79+
case 3: return new String[] {
80+
// Xcomp Only C1.
81+
"-XX:TieredStopAtLevel=1",
82+
"-XX:+TieredCompilation",
83+
"-Xcomp",
84+
};
85+
case 4: return new String[] {
86+
// Xcomp Only C2.
87+
"-XX:TieredStopAtLevel=4",
88+
"-XX:-TieredCompilation",
89+
"-XX:-OmitStackTraceInFastThrow",
90+
"-Xcomp",
91+
};
92+
}
93+
return null;
94+
}
95+
96+
// Simple chain of getfields ending with primitive field
97+
@Test(compLevel=C1)
98+
public int test1() {
99+
return NamedRectangle.getP1X(new NamedRectangle());
100+
}
101+
102+
@DontCompile
103+
public void test1_verifier(boolean warmup) {
104+
int res = test1();
105+
Asserts.assertEQ(res, 4);
106+
}
107+
108+
// Simple chain of getfields ending with a flattened field
109+
@Test(compLevel=C1)
110+
public Point test2() {
111+
return NamedRectangle.getP1(new NamedRectangle());
112+
}
113+
114+
@DontCompile
115+
public void test2_verifier(boolean warmup) {
116+
Point p = test2();
117+
Asserts.assertEQ(p.x, 4);
118+
Asserts.assertEQ(p.y, 7);
119+
}
120+
121+
// Chain of getfields but the initial receiver is null
122+
@Test(compLevel=C1)
123+
public NullPointerException test3() {
124+
NullPointerException npe = null;
125+
try {
126+
NamedRectangle.getP1X(null);
127+
} catch(NullPointerException e) {
128+
npe = e;
129+
}
130+
return npe;
131+
}
132+
133+
@DontCompile
134+
public void test3_verifier(boolean warmup) {
135+
NullPointerException npe = test3();
136+
Asserts.assertNE(npe, null);
137+
StackTraceElement st = npe.getStackTrace()[0];
138+
Asserts.assertEQ(st.getMethodName(), "getP1X");
139+
Asserts.assertEQ(st.getLineNumber(), 31); // line number depends on file NamedRectangle.java
140+
}
141+
142+
// Chain of getfields but one getfield in the middle of the chain trigger an illegal access
143+
@Test(compLevel=C1)
144+
public IllegalAccessError test4() {
145+
IllegalAccessError iae = null;
146+
try {
147+
int i = NamedRectangleP.getP1X(new NamedRectangleP());
148+
} catch(IllegalAccessError e) {
149+
iae = e;
150+
}
151+
return iae;
152+
}
153+
154+
@DontCompile
155+
public void test4_verifier(boolean warmup) {
156+
IllegalAccessError iae = test4();
157+
Asserts.assertNE(iae, null);
158+
StackTraceElement st = iae.getStackTrace()[0];
159+
Asserts.assertEQ(st.getMethodName(), "getP1X");
160+
Asserts.assertEQ(st.getLineNumber(), 31); // line number depends on jcod file generated from NamedRectangle.java
161+
Asserts.assertTrue(iae.getMessage().contains("class compiler.valhalla.inlinetypes.NamedRectangleP tried to access private field compiler.valhalla.inlinetypes.RectangleP.p1"));
162+
}
163+
164+
// Chain of getfields but the last getfield trigger a NoSuchFieldError
165+
@Test(compLevel=C1)
166+
public NoSuchFieldError test5() {
167+
NoSuchFieldError nsfe = null;
168+
try {
169+
int i = NamedRectangleN.getP1X(new NamedRectangleN());
170+
} catch(NoSuchFieldError e) {
171+
nsfe = e;
172+
}
173+
return nsfe;
174+
}
175+
176+
@DontCompile
177+
public void test5_verifier(boolean warmup) {
178+
NoSuchFieldError nsfe = test5();
179+
Asserts.assertNE(nsfe, null);
180+
StackTraceElement st = nsfe.getStackTrace()[0];
181+
Asserts.assertEQ(st.getMethodName(), "getP1X");
182+
Asserts.assertEQ(st.getLineNumber(), 31); // line number depends on jcod file generated from NamedRectangle.java
183+
Asserts.assertEQ(nsfe.getMessage(), "x");
184+
}
185+
}

0 commit comments

Comments
 (0)
Please sign in to comment.