Skip to content

Commit c0c4a50

Browse files
committed
Update String model class to comply with JEP 254
Due to the implementation changes made to the standard Java String and related classes in JEP 254 (Java 9 and later), JPF String model class now fails to compile. This updates String model class to comply with the internal API changes. This make String model class to follow a internal representation similar to the standard String class in Java 9 and later which uses byte array plus an encoding-flag field instead of UTF-16 char array to represent a String. Fixes: #37
1 parent 710d8cf commit c0c4a50

File tree

1 file changed

+70
-22
lines changed

1 file changed

+70
-22
lines changed

src/classes/modules/java.base/java/lang/String.java

Lines changed: 70 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,18 @@ public final class String
4545
implements java.io.Serializable, Comparable<String>, CharSequence {
4646

4747
/** The value is used for character storage. */
48-
private final char value[];
48+
private final byte value[];
49+
50+
/**
51+
* The identifier of the encoding used to encode the bytes in
52+
* The supported values in this implementation are:
53+
* LATIN1
54+
* UTF16
55+
*/
56+
private final byte coder;
57+
58+
static final byte LATIN1 = 0;
59+
static final byte UTF16 = 1;
4960

5061
/** Cache the hash code for the string */
5162
private int hash; // Default to 0
@@ -57,25 +68,28 @@ public final class String
5768
new ObjectStreamField[0];
5869

5970
public String() {
60-
this.value = new char[0];
71+
this.value = "".value;
72+
this.coder = "".coder;
6173
}
6274

6375
public String(String original) {
6476
this.value = original.value;
77+
this.coder = original.coder;
6578
this.hash = original.hash;
6679
}
6780

6881
public String(char value[]) {
69-
this.value = Arrays.copyOf(value, value.length);
82+
this((char[]) value, 0, value.length, (Void) null);
7083
}
7184

7285
public String(char value[], boolean share) {
73-
this.value = Arrays.copyOf(value, value.length);
86+
this((char[]) value, 0, value.length, (Void) null);
7487
}
7588

7689
public String(char value[], int offset, int count) {
7790
String proxy=init(value,offset,count);
7891
this.value=proxy.value;
92+
this.coder=proxy.coder;
7993
this.hash=proxy.hash;
8094
}
8195

@@ -84,6 +98,7 @@ public String(char value[], int offset, int count) {
8498
public String(int[] codePoints, int offset, int count) {
8599
String proxy=init(codePoints,offset,count);
86100
this.value=proxy.value;
101+
this.coder=proxy.coder;
87102
this.hash=proxy.hash;
88103
}
89104

@@ -93,6 +108,7 @@ public String(int[] codePoints, int offset, int count) {
93108
public String(byte ascii[], int hibyte, int offset, int count) {
94109
String proxy=init(ascii,hibyte,offset,count);
95110
this.value=proxy.value;
111+
this.coder=proxy.coder;
96112
this.hash=proxy.hash;
97113
}
98114

@@ -108,6 +124,7 @@ public String(byte ascii[], int hibyte) {
108124
public String(byte bytes[], int offset, int length, String charsetName){
109125
String proxy=init(bytes,offset,length,charsetName);
110126
this.value=proxy.value;
127+
this.coder=proxy.coder;
111128
this.hash=proxy.hash;
112129
}
113130

@@ -129,7 +146,9 @@ public String(byte x[], int offset, int length, Charset cset) {
129146
throw new StringIndexOutOfBoundsException(offset + length);
130147
}
131148

132-
this.value = StringCoding.decode(cset, x, offset, length);
149+
StringCoding.Result result = StringCoding.decode(cset, x, offset, length);
150+
this.value = result.value;
151+
this.coder = result.coder;
133152
}
134153

135154
public String(byte bytes[], String charsetName)
@@ -144,6 +163,7 @@ public String(byte bytes[], Charset charset) {
144163
public String(byte bytes[], int offset, int length) {
145164
String proxy=init(bytes,offset,length);
146165
this.value=proxy.value;
166+
this.coder=proxy.coder;
147167
this.hash=proxy.hash;
148168
}
149169

@@ -156,14 +176,30 @@ public String(byte bytes[]) {
156176

157177

158178
public String(StringBuffer x) {
159-
synchronized(x) {
160-
this.value = Arrays.copyOf(x.getValue(), x.length());
161-
}
179+
this(x.toString());
162180
}
163181

164182

165183
public String(StringBuilder x) {
166184
this.value = Arrays.copyOf(x.getValue(), x.length());
185+
this.coder = x.coder;
186+
}
187+
188+
String(char[] value, int off, int len, Void sig) {
189+
if (len == 0) {
190+
this.value = "".value;
191+
this.coder = "".coder;
192+
} else {
193+
byte[] val = StringUTF16.compress(value, off, len);
194+
if (val != null) {
195+
this.value = val;
196+
this.coder = LATIN1;
197+
return;
198+
}
199+
200+
this.coder = UTF16;
201+
this.value = StringUTF16.toBytes(value, off, len);
202+
}
167203
}
168204

169205
@Deprecated
@@ -182,7 +218,7 @@ public char charAt(int index) {
182218
if ((index < 0) || (index >= value.length)) {
183219
throw new StringIndexOutOfBoundsException(index);
184220
}
185-
return value[index];
221+
return this.isLatin1() ? StringLatin1.charAt(this.value, index) : StringUTF16.charAt(this.value, index);
186222
}
187223

188224
native public int codePointAt(int index);
@@ -202,7 +238,7 @@ public byte[] getBytes(Charset x){
202238
if (x == null){
203239
throw new NullPointerException();
204240
}
205-
return StringCoding.encode(x, value, 0, value.length);
241+
return StringCoding.encode(x, this.coder, this.value);
206242
}
207243

208244
native public byte[] getBytes();
@@ -224,25 +260,34 @@ public boolean contentEquals(StringBuffer stringBuffer){
224260
public boolean contentEquals (CharSequence charSequence){
225261
if (value.length != charSequence.length()){
226262
return false;
227-
}
263+
}
228264

229-
// that should be the common case (String)
265+
// that should be the common case (String)
230266
if (charSequence.equals(this)){
231267
return true;
232268
}
233-
234-
// we can do that natively, too
269+
270+
// we can do that natively, too
235271
if (charSequence instanceof AbstractStringBuilder) {
236-
return equals0( value, ((AbstractStringBuilder) charSequence).getValue(), value.length);
272+
byte[] val = ((AbstractStringBuilder) charSequence).getValue();
273+
byte coder = ((AbstractStringBuilder) charSequence).getCoder();
274+
assert coder == UTF16 : "Currently only UTF16 is supported for String comparision with an instance of type AbstractStringBuilder";
275+
return StringUTF16.contentEquals(this.value, val, this.length());
237276
}
238277

239278
// generic CharSequence - expensive
240-
char v[] = value;
241-
for (int n=value.length, i=0; n >= 0; n--,i++){
242-
if (v[i] != charSequence.charAt(i)){
243-
return false;
244-
}
245-
}
279+
int n = charSequence.length();
280+
byte[] val = this.value;
281+
if (isLatin1()) {
282+
for (int i = 0; i < n; i++) {
283+
if ((val[i] & 0xff) != charSequence.charAt(i)) {
284+
return false;
285+
}
286+
}
287+
} else {
288+
return StringUTF16.contentEquals(val, charSequence, n);
289+
}
290+
246291
return true;
247292
}
248293

@@ -356,7 +401,10 @@ public static String valueOf(char character) {
356401
native public static String valueOf(double d);
357402
public native String intern();
358403

359-
404+
private boolean isLatin1() {
405+
return this.coder == LATIN1;
406+
}
407+
360408
/*
361409
* methods to be compatible with Harmony/Android, which now has modified
362410
* versions of the old (offset based) String

0 commit comments

Comments
 (0)