Skip to content

Commit 7af927f

Browse files
TobiHartmannbchristi-gitVivek Deshpandehuntchvnkozlov
committed
8141132: JEP 254: Compact Strings
Adopt a more space-efficient internal representation for strings. Co-authored-by: Brent Christian <brent.christian@oracle.com> Co-authored-by: Vivek Deshpande <vivek.r.deshpande@intel.com> Co-authored-by: Charlie Hunt <charlie.hunt@oracle.com> Co-authored-by: Vladimir Kozlov <vladimir.kozlov@oracle.com> Co-authored-by: Roger Riggs <roger.riggs@oracle.com> Co-authored-by: Xueming Shen <xueming.shen@oracle.com> Co-authored-by: Aleksey Shipilev <aleksey.shipilev@oracle.com> Co-authored-by: Sandhya Viswanathan <sandhya.viswanathan@intel.com> Reviewed-by: alanb, bdelsart, coleenp, iklam, jiangli, jrose, kevinw, naoto, pliden, roland, smarks, twisti
1 parent 4e24e2c commit 7af927f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

74 files changed

+4817
-1662
lines changed

hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/OopUtilities.java

Lines changed: 27 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,7 @@ public class OopUtilities implements /* imports */ JVMTIThreadState {
4040
// FIXME: access should be synchronized and cleared when VM is
4141
// resumed
4242
// String fields
43-
private static IntField offsetField;
44-
private static IntField countField;
43+
private static ByteField coderField;
4544
private static OopField valueField;
4645
// ThreadGroup fields
4746
private static OopField threadGroupParentField;
@@ -96,20 +95,30 @@ public static String charArrayToString(TypeArray charArray) {
9695
if (charArray == null) {
9796
return null;
9897
}
99-
return charArrayToString(charArray, 0, (int) charArray.getLength());
98+
int length = (int)charArray.getLength();
99+
StringBuffer buf = new StringBuffer(length);
100+
for (int i = 0; i < length; i++) {
101+
buf.append(charArray.getCharAt(i));
102+
}
103+
return buf.toString();
100104
}
101105

102-
public static String charArrayToString(TypeArray charArray, int offset, int length) {
103-
if (charArray == null) {
106+
public static String byteArrayToString(TypeArray byteArray, byte coder) {
107+
if (byteArray == null) {
104108
return null;
105109
}
106-
final int limit = offset + length;
107-
if (Assert.ASSERTS_ENABLED) {
108-
Assert.that(offset >= 0 && limit <= charArray.getLength(), "out of bounds");
109-
}
110+
int length = (int)byteArray.getLength() >> coder;
110111
StringBuffer buf = new StringBuffer(length);
111-
for (int i = offset; i < limit; i++) {
112-
buf.append(charArray.getCharAt(i));
112+
if (coder == 0) {
113+
// Latin1 encoded
114+
for (int i = 0; i < length; i++) {
115+
buf.append((char)(byteArray.getByteAt(i) & 0xff));
116+
}
117+
} else {
118+
// UTF16 encoded
119+
for (int i = 0; i < length; i++) {
120+
buf.append(byteArray.getCharAt(i));
121+
}
113122
}
114123
return buf.toString();
115124
}
@@ -141,21 +150,14 @@ public static String escapeString(String s) {
141150
}
142151

143152
public static String stringOopToString(Oop stringOop) {
144-
if (offsetField == null) {
145-
InstanceKlass k = (InstanceKlass) stringOop.getKlass();
146-
offsetField = (IntField) k.findField("offset", "I"); // optional
147-
countField = (IntField) k.findField("count", "I"); // optional
148-
valueField = (OopField) k.findField("value", "[C");
149-
if (Assert.ASSERTS_ENABLED) {
150-
Assert.that(valueField != null, "Field \'value\' of java.lang.String not found");
151-
}
152-
}
153-
if (offsetField != null && countField != null) {
154-
return charArrayToString((TypeArray) valueField.getValue(stringOop),
155-
offsetField.getValue(stringOop),
156-
countField.getValue(stringOop));
153+
InstanceKlass k = (InstanceKlass) stringOop.getKlass();
154+
coderField = (ByteField) k.findField("coder", "B");
155+
valueField = (OopField) k.findField("value", "[B");
156+
if (Assert.ASSERTS_ENABLED) {
157+
Assert.that(coderField != null, "Field \'coder\' of java.lang.String not found");
158+
Assert.that(valueField != null, "Field \'value\' of java.lang.String not found");
157159
}
158-
return charArrayToString((TypeArray) valueField.getValue(stringOop));
160+
return byteArrayToString((TypeArray) valueField.getValue(stringOop), coderField.getValue(stringOop));
159161
}
160162

161163
public static String stringOopToEscapedString(Oop stringOop) {

hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/HeapSummary.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -268,8 +268,8 @@ class StringStat implements StringTable.StringVisitor {
268268
VM vm = VM.getVM();
269269
SystemDictionary sysDict = vm.getSystemDictionary();
270270
InstanceKlass strKlass = sysDict.getStringKlass();
271-
// String has a field named 'value' of type 'char[]'.
272-
stringValueField = (OopField) strKlass.findField("value", "[C");
271+
// String has a field named 'value' of type 'byte[]'.
272+
stringValueField = (OopField) strKlass.findField("value", "[B");
273273
}
274274

275275
private long stringSize(Instance instance) {

hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/Hashtable.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,8 @@ protected static long hashSymbol(byte[] buf) {
6161
long h = 0;
6262
int s = 0;
6363
int len = buf.length;
64-
// Emulate the unsigned int in java_lang_String::hash_code
6564
while (len-- > 0) {
66-
h = 31*h + (0xFFFFFFFFL & buf[s]);
65+
h = 31*h + (0xFFL & buf[s]);
6766
s++;
6867
}
6968
return h & 0xFFFFFFFFL;

hotspot/src/cpu/aarch64/vm/aarch64.ad

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14150,6 +14150,7 @@ instruct partialSubtypeCheckVsZero(iRegP_R4 sub, iRegP_R0 super, iRegP_R2 temp,
1415014150
instruct string_compare(iRegP_R1 str1, iRegI_R2 cnt1, iRegP_R3 str2, iRegI_R4 cnt2,
1415114151
iRegI_R0 result, iRegP_R10 tmp1, rFlagsReg cr)
1415214152
%{
14153+
predicate(!CompactStrings);
1415314154
match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2)));
1415414155
effect(KILL tmp1, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL cr);
1415514156

@@ -14165,6 +14166,7 @@ instruct string_compare(iRegP_R1 str1, iRegI_R2 cnt1, iRegP_R3 str2, iRegI_R4 cn
1416514166
instruct string_indexof(iRegP_R1 str1, iRegI_R4 cnt1, iRegP_R3 str2, iRegI_R2 cnt2,
1416614167
iRegI_R0 result, iRegI tmp1, iRegI tmp2, iRegI tmp3, iRegI tmp4, rFlagsReg cr)
1416714168
%{
14169+
predicate(!CompactStrings);
1416814170
match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 cnt2)));
1416914171
effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2,
1417014172
TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, KILL cr);
@@ -14184,6 +14186,7 @@ instruct string_indexof_con(iRegP_R1 str1, iRegI_R4 cnt1, iRegP_R3 str2,
1418414186
immI_le_4 int_cnt2, iRegI_R0 result, iRegI tmp1, iRegI tmp2,
1418514187
iRegI tmp3, iRegI tmp4, rFlagsReg cr)
1418614188
%{
14189+
predicate(!CompactStrings);
1418714190
match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 int_cnt2)));
1418814191
effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt1,
1418914192
TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, KILL cr);
@@ -14203,6 +14206,7 @@ instruct string_indexof_con(iRegP_R1 str1, iRegI_R4 cnt1, iRegP_R3 str2,
1420314206
instruct string_equals(iRegP_R1 str1, iRegP_R3 str2, iRegI_R4 cnt,
1420414207
iRegI_R0 result, iRegP_R10 tmp, rFlagsReg cr)
1420514208
%{
14209+
predicate(!CompactStrings);
1420614210
match(Set result (StrEquals (Binary str1 str2) cnt));
1420714211
effect(KILL tmp, USE_KILL str1, USE_KILL str2, USE_KILL cnt, KILL cr);
1420814212

@@ -14218,6 +14222,7 @@ instruct string_equals(iRegP_R1 str1, iRegP_R3 str2, iRegI_R4 cnt,
1421814222
instruct array_equals(iRegP_R1 ary1, iRegP_R2 ary2, iRegI_R0 result,
1421914223
iRegP_R10 tmp, rFlagsReg cr)
1422014224
%{
14225+
predicate(((AryEqNode*)n)->encoding() == StrIntrinsicNode::UU);
1422114226
match(Set result (AryEq ary1 ary2));
1422214227
effect(KILL tmp, USE_KILL ary1, USE_KILL ary2, KILL cr);
1422314228

hotspot/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.cpp

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -483,15 +483,6 @@ int LIR_Assembler::emit_deopt_handler() {
483483
return offset;
484484
}
485485

486-
487-
// This is the fast version of java.lang.String.compare; it has not
488-
// OSR-entry and therefore, we generate a slow version for OSR's
489-
void LIR_Assembler::emit_string_compare(LIR_Opr arg0, LIR_Opr arg1, LIR_Opr dst, CodeEmitInfo* info) {
490-
__ mov(r2, (address)__FUNCTION__);
491-
__ call_Unimplemented();
492-
}
493-
494-
495486
void LIR_Assembler::add_debug_info_for_branch(address adr, CodeEmitInfo* info) {
496487
_masm->code_section()->relocate(adr, relocInfo::poll_type);
497488
int pc_offset = code_offset();

hotspot/src/cpu/aarch64/vm/globals_aarch64.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,9 @@ define_pd_global(uintx, CMSYoungGenPerWorker, 64*M); // default max size of CMS
7979

8080
define_pd_global(uintx, TypeProfileLevel, 111);
8181

82+
// No performance work done here yet.
83+
define_pd_global(bool, CompactStrings, false);
84+
8285
// avoid biased locking while we are bootstrapping the aarch64 build
8386
define_pd_global(bool, UseBiasedLocking, false);
8487

hotspot/src/cpu/ppc/vm/globals_ppc.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@ define_pd_global(size_t, CMSYoungGenPerWorker, 16*M); // Default max size of CM
7272

7373
define_pd_global(uintx, TypeProfileLevel, 111);
7474

75+
// No performance work done here yet.
76+
define_pd_global(bool, CompactStrings, false);
77+
7578
// Platform dependent flag handling: flags only defined on this platform.
7679
#define ARCH_FLAGS(develop, product, diagnostic, experimental, notproduct, range, constraint) \
7780
\

hotspot/src/cpu/ppc/vm/ppc.ad

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2054,11 +2054,11 @@ const bool Matcher::match_rule_supported(int opcode) {
20542054
return (UsePopCountInstruction && VM_Version::has_popcntw());
20552055

20562056
case Op_StrComp:
2057-
return SpecialStringCompareTo;
2057+
return SpecialStringCompareTo && !CompactStrings;
20582058
case Op_StrEquals:
2059-
return SpecialStringEquals;
2059+
return SpecialStringEquals && !CompactStrings;
20602060
case Op_StrIndexOf:
2061-
return SpecialStringIndexOf;
2061+
return SpecialStringIndexOf && !CompactStrings;
20622062
}
20632063

20642064
return true; // Per default match rules are supported.
@@ -11077,7 +11077,7 @@ instruct string_indexOf_imm1_char(iRegIdst result, iRegPsrc haystack, iRegIsrc h
1107711077
immP needleImm, immL offsetImm, immI_1 needlecntImm,
1107811078
iRegIdst tmp1, iRegIdst tmp2,
1107911079
flagsRegCR0 cr0, flagsRegCR1 cr1) %{
11080-
predicate(SpecialStringIndexOf); // type check implicit by parameter type, See Matcher::match_rule_supported
11080+
predicate(SpecialStringIndexOf && !CompactStrings); // type check implicit by parameter type, See Matcher::match_rule_supported
1108111081
match(Set result (StrIndexOf (Binary haystack haycnt) (Binary (AddP needleImm offsetImm) needlecntImm)));
1108211082

1108311083
effect(TEMP_DEF result, TEMP tmp1, TEMP tmp2, KILL cr0, KILL cr1);
@@ -11120,7 +11120,7 @@ instruct string_indexOf_imm1(iRegIdst result, iRegPsrc haystack, iRegIsrc haycnt
1112011120
effect(USE_KILL needle, /* TDEF needle, */ TEMP_DEF result,
1112111121
TEMP tmp1, TEMP tmp2);
1112211122
// Required for EA: check if it is still a type_array.
11123-
predicate(SpecialStringIndexOf && n->in(3)->in(1)->bottom_type()->is_aryptr()->const_oop() &&
11123+
predicate(SpecialStringIndexOf && !CompactStrings && n->in(3)->in(1)->bottom_type()->is_aryptr()->const_oop() &&
1112411124
n->in(3)->in(1)->bottom_type()->is_aryptr()->const_oop()->is_type_array());
1112511125
ins_cost(180);
1112611126

@@ -11167,7 +11167,7 @@ instruct string_indexOf_imm(iRegIdst result, iRegPsrc haystack, rscratch1RegI ha
1116711167
effect(USE_KILL haycnt, /* better: TDEF haycnt, */ TEMP_DEF result,
1116811168
TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, TEMP tmp5, KILL cr0, KILL cr1, KILL cr6);
1116911169
// Required for EA: check if it is still a type_array.
11170-
predicate(SpecialStringIndexOf && n->in(3)->in(1)->bottom_type()->is_aryptr()->const_oop() &&
11170+
predicate(SpecialStringIndexOf && !CompactStrings && n->in(3)->in(1)->bottom_type()->is_aryptr()->const_oop() &&
1117111171
n->in(3)->in(1)->bottom_type()->is_aryptr()->const_oop()->is_type_array());
1117211172
ins_cost(250);
1117311173

@@ -11200,7 +11200,7 @@ instruct string_indexOf(iRegIdst result, iRegPsrc haystack, rscratch1RegI haycnt
1120011200
effect(USE_KILL haycnt, USE_KILL needlecnt, /*better: TDEF haycnt, TDEF needlecnt,*/
1120111201
TEMP_DEF result,
1120211202
TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, KILL cr0, KILL cr1, KILL cr6);
11203-
predicate(SpecialStringIndexOf); // See Matcher::match_rule_supported.
11203+
predicate(SpecialStringIndexOf && !CompactStrings); // See Matcher::match_rule_supported.
1120411204
ins_cost(300);
1120511205

1120611206
ins_alignment(8); // 'compute_padding()' gets called, up to this number-1 nops will get inserted.
@@ -11224,7 +11224,7 @@ instruct string_equals_imm(iRegPsrc str1, iRegPsrc str2, uimmI15 cntImm, iRegIds
1122411224
match(Set result (StrEquals (Binary str1 str2) cntImm));
1122511225
effect(TEMP_DEF result, TEMP tmp1, TEMP tmp2,
1122611226
KILL cr0, KILL cr6, KILL ctr);
11227-
predicate(SpecialStringEquals); // See Matcher::match_rule_supported.
11227+
predicate(SpecialStringEquals && !CompactStrings); // See Matcher::match_rule_supported.
1122811228
ins_cost(250);
1122911229

1123011230
ins_alignment(8); // 'compute_padding()' gets called, up to this number-1 nops will get inserted.
@@ -11247,7 +11247,7 @@ instruct string_equals(iRegPsrc str1, iRegPsrc str2, iRegIsrc cnt, iRegIdst resu
1124711247
match(Set result (StrEquals (Binary str1 str2) cnt));
1124811248
effect(TEMP_DEF result, TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, TEMP tmp5,
1124911249
KILL cr0, KILL cr1, KILL cr6, KILL ctr);
11250-
predicate(SpecialStringEquals); // See Matcher::match_rule_supported.
11250+
predicate(SpecialStringEquals && !CompactStrings); // See Matcher::match_rule_supported.
1125111251
ins_cost(300);
1125211252

1125311253
ins_alignment(8); // 'compute_padding()' gets called, up to this number-1 nops will get inserted.
@@ -11267,6 +11267,7 @@ instruct string_equals(iRegPsrc str1, iRegPsrc str2, iRegIsrc cnt, iRegIdst resu
1126711267
// Use dst register classes if register gets killed, as it is the case for TEMP operands!
1126811268
instruct string_compare(rarg1RegP str1, rarg2RegP str2, rarg3RegI cnt1, rarg4RegI cnt2, iRegIdst result,
1126911269
iRegPdst tmp, flagsRegCR0 cr0, regCTR ctr) %{
11270+
predicate(!CompactStrings);
1127011271
match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2)));
1127111272
effect(USE_KILL cnt1, USE_KILL cnt2, USE_KILL str1, USE_KILL str2, TEMP_DEF result, TEMP tmp, KILL cr0, KILL ctr);
1127211273
ins_cost(300);

hotspot/src/cpu/sparc/vm/assembler_sparc.hpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,8 @@ class Assembler : public AbstractAssembler {
124124
impdep1_op3 = 0x36,
125125
aes3_op3 = 0x36,
126126
sha_op3 = 0x36,
127+
bmask_op3 = 0x36,
128+
bshuffle_op3 = 0x36,
127129
alignaddr_op3 = 0x36,
128130
faligndata_op3 = 0x36,
129131
flog3_op3 = 0x36,
@@ -194,6 +196,7 @@ class Assembler : public AbstractAssembler {
194196
fnegd_opf = 0x06,
195197

196198
alignaddr_opf = 0x18,
199+
bmask_opf = 0x19,
197200

198201
fadds_opf = 0x41,
199202
faddd_opf = 0x42,
@@ -204,6 +207,7 @@ class Assembler : public AbstractAssembler {
204207

205208
fmuls_opf = 0x49,
206209
fmuld_opf = 0x4a,
210+
bshuffle_opf = 0x4c,
207211
fdivs_opf = 0x4d,
208212
fdivd_opf = 0x4e,
209213

@@ -1226,6 +1230,9 @@ class Assembler : public AbstractAssembler {
12261230

12271231
void edge8n( Register s1, Register s2, Register d ) { vis2_only(); emit_int32( op(arith_op) | rd(d) | op3(edge_op3) | rs1(s1) | opf(edge8n_opf) | rs2(s2)); }
12281232

1233+
void bmask( Register s1, Register s2, Register d ) { vis2_only(); emit_int32( op(arith_op) | rd(d) | op3(bmask_op3) | rs1(s1) | opf(bmask_opf) | rs2(s2)); }
1234+
void bshuffle( FloatRegister s1, FloatRegister s2, FloatRegister d ) { vis2_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(bshuffle_op3) | fs1(s1, FloatRegisterImpl::D) | opf(bshuffle_opf) | fs2(s2, FloatRegisterImpl::D)); }
1235+
12291236
// VIS3 instructions
12301237

12311238
void movstosw( FloatRegister s, Register d ) { vis3_only(); emit_int32( op(arith_op) | rd(d) | op3(mftoi_op3) | opf(mstosw_opf) | fs2(s, FloatRegisterImpl::S)); }

0 commit comments

Comments
 (0)