Fixing a bug in JPF_java_lang_String.java: There was a bug in the loop of the native...
[jpf-core.git] / src / peers / gov / nasa / jpf / vm / JPF_java_lang_String.java
1 /*
2  * Copyright (C) 2014, United States Government, as represented by the
3  * Administrator of the National Aeronautics and Space Administration.
4  * All rights reserved.
5  *
6  * The Java Pathfinder core (jpf-core) platform is licensed under the
7  * Apache License, Version 2.0 (the "License"); you may not use this file except
8  * in compliance with the License. You may obtain a copy of the License at
9  * 
10  *        http://www.apache.org/licenses/LICENSE-2.0. 
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and 
16  * limitations under the License.
17  */
18 package gov.nasa.jpf.vm;
19
20 import gov.nasa.jpf.annotation.MJI;
21 import gov.nasa.jpf.vm.CharArrayFields;
22 import gov.nasa.jpf.vm.ElementInfo;
23 import gov.nasa.jpf.vm.Fields;
24 import gov.nasa.jpf.vm.Heap;
25 import gov.nasa.jpf.vm.MJIEnv;
26 import gov.nasa.jpf.vm.NativePeer;
27
28 import java.io.UnsupportedEncodingException;
29 import java.util.Locale;
30
31 /**
32  * MJI NativePeer class for java.lang.String library abstraction
33  */
34 public class JPF_java_lang_String extends NativePeer {
35   final static String sioobe = "java.lang.StringIndexOutOfBoundsException";
36   final static String sioor = "String index out of range: ";
37   
38   @MJI
39   public int init___3CII__Ljava_lang_String_2 (MJIEnv env, int objRef, int valueRef, int offset, int count) {
40     char[] value = env.getCharArrayObject(valueRef);
41     String result = new String(value, offset, count);
42     return env.newString(result);
43   }
44
45   @MJI
46   public int init___3III__Ljava_lang_String_2 (MJIEnv env, int objRef, int codePointsRef, int offset, int count) {
47     int[] codePoints = env.getIntArrayObject(codePointsRef);
48     String result = new String(codePoints, offset, count);
49     return env.newString(result);
50   }
51
52   @SuppressWarnings("deprecation")
53   @MJI
54   public int init___3BIII__Ljava_lang_String_2 (MJIEnv env, int objRef, int asciiRef, int hibyte, int offset, int count) {
55     byte[] ascii = env.getByteArrayObject(asciiRef);
56     String result = new String(ascii, hibyte, offset, count);
57     return env.newString(result);
58   }
59
60   @MJI
61   public int init___3BIILjava_lang_String_2__Ljava_lang_String_2 (MJIEnv env, int objRef, int bytesRef, int offset, int length, int charsetNameRef) throws UnsupportedEncodingException {
62     byte[] bytes = env.getByteArrayObject(bytesRef);
63     String charsetName = env.getStringObject(charsetNameRef);
64     String result = new String(bytes, offset, length, charsetName);
65     return env.newString(result);
66   }
67
68   @MJI
69   public int init___3BII__Ljava_lang_String_2 (MJIEnv env, int objRef, int bytesRef, int offset, int length) {
70     byte[] bytes = env.getByteArrayObject(bytesRef);
71     String result = new String(bytes, offset, length);
72     return env.newString(result);
73   }
74
75   @MJI
76   public int codePointAt__I__I (MJIEnv env, int objRef, int index) {
77     String obj = env.getStringObject(objRef);
78     return obj.codePointAt(index);
79   }
80
81   @MJI
82   public int codePointBefore__I__I (MJIEnv env, int objRef, int index) {
83     String obj = env.getStringObject(objRef);
84     return obj.codePointBefore(index);
85   }
86
87   @MJI
88   public int codePointCount__II__I (MJIEnv env, int objRef, int beginIndex, int endIndex) {
89     String obj = env.getStringObject(objRef);
90     return obj.codePointCount(beginIndex, endIndex);
91   }
92
93   @MJI
94   public int offsetByCodePoints__II__I (MJIEnv env, int objRef, int index, int codePointOffset) {
95     String obj = env.getStringObject(objRef);
96     return obj.offsetByCodePoints(index, codePointOffset);
97   }
98
99   @MJI
100   public void getChars__II_3CI__V (MJIEnv env, int objRef, int srcBegin, int srcEnd, int dstRef, int dstBegin) {
101     String obj = env.getStringObject(objRef);
102     char[] dst = env.getCharArrayObject(dstRef);
103     obj.getChars(srcBegin, srcEnd, dst, dstBegin);
104   }
105
106   @MJI
107   public void getChars___3CI__V(MJIEnv env, int objRef, int dstRef, int dstBegin) {
108     String obj = env.getStringObject(objRef);
109     char[] dst = env.getCharArrayObject(dstRef);
110     obj.getChars(0, obj.length(), dst, dstBegin);
111   }
112   
113   @SuppressWarnings("deprecation")
114   @MJI
115   public void getBytes__II_3BI__V (MJIEnv env, int objRef, int srcBegin, int srcEnd, int dstRef, int dstBegin) {
116     String obj = env.getStringObject(objRef);
117     byte[] dst = env.getByteArrayObject(dstRef);
118     obj.getBytes(srcBegin, srcEnd, dst, dstBegin);
119   }
120
121   @MJI
122   public int getBytes__Ljava_lang_String_2___3B (MJIEnv env, int objRef, int charSetRef) {
123     String string = env.getStringObject(objRef);
124     String charset = env.getStringObject(charSetRef);
125
126     try {
127       byte[] b = string.getBytes(charset);
128       return env.newByteArray(b);
129
130     } catch (UnsupportedEncodingException uex) {
131       env.throwException(uex.getClass().getName(), uex.getMessage());
132       return MJIEnv.NULL;
133     }
134   }
135
136   @MJI
137   public int getBytes_____3B (MJIEnv env, int objRef) {
138     String obj = env.getStringObject(objRef);
139     byte[] bytes = obj.getBytes();
140     return env.newByteArray(bytes);
141   }
142
143   @MJI
144   public char charAt__I__C (MJIEnv env, int objRef, int index){
145     char[] data = env.getStringChars(objRef);
146     if (index >= 0 && index < data.length) {
147       return data[index];
148     }
149     env.throwException(sioobe, sioor + index);
150     return '\0';
151   }
152
153   
154   @MJI
155   public boolean equals0___3C_3CI__Z (MJIEnv env, int clsObjRef, int charsRef1, int charsRef2, int len) {
156
157     if ((charsRef1 == MJIEnv.NULL) || (charsRef2 == MJIEnv.NULL)) { return false; }
158
159     char[] a = env.getCharArrayObject(charsRef1);
160     char[] b = env.getCharArrayObject(charsRef2);
161
162     if (a.length < len || b.length < len) { return false; }
163
164     for (int i = 0; i < len; i++) {
165       if (a[i] != b[i]) { return false; }
166     }
167
168     return true;
169   }
170
171   @MJI
172   public boolean equals__Ljava_lang_Object_2__Z (MJIEnv env, int objRef, int argRef) {
173     if (argRef == MJIEnv.NULL) { 
174       return false; 
175     }
176
177     Heap heap = env.getHeap();
178     ElementInfo s1 = heap.get(objRef);
179     ClassInfo ci1 = s1.getClassInfo();
180     
181     ElementInfo s2 = heap.get(argRef);
182     ClassInfo ci2 = s2.getClassInfo();
183    
184     if (!ci2.isInstanceOf(ci1)) { 
185       return false;
186     }
187
188     Fields f1 = heap.get(s1.getReferenceField("value")).getFields();
189     Fields f2 = heap.get(s2.getReferenceField("value")).getFields();
190
191     char[] c1 = ((CharArrayFields) f1).asCharArray();
192     char[] c2 = ((CharArrayFields) f2).asCharArray();
193
194     if (c1.length != c2.length) { 
195       return false; 
196     }
197
198     for (int i = 0; i < c1.length; i++) {
199       if (c1[i] != c2[i]) { 
200         return false; 
201       }
202     }
203
204     return true;
205   }
206
207   @MJI
208   public boolean equalsIgnoreCase__Ljava_lang_String_2__Z (MJIEnv env, int objref, int anotherString) {
209     String thisString = env.getStringObject(objref);
210     if (anotherString != MJIEnv.NULL) {
211       return thisString.equalsIgnoreCase(env.getStringObject(anotherString));
212     } else {
213       return false;
214     }
215   }
216
217   @MJI
218   public int compareTo__Ljava_lang_String_2__I (MJIEnv env, int objRef, int anotherStringRef) {
219     String obj = env.getStringObject(objRef);
220     String anotherString = env.getStringObject(anotherStringRef);
221     return obj.compareTo(anotherString);
222   }
223
224   @MJI
225   public int MJIcompare__Ljava_lang_String_2Ljava_lang_String_2__I (MJIEnv env, int clsRef, int s1Ref, int s2Ref) {
226     // Is there a way to reflect?
227     String a = env.getStringObject(s1Ref);
228     String s2 = env.getStringObject(s2Ref);
229     int n1 = a.length();
230     int n2 = s2.length();
231     int min = Math.min(n1, n2);
232     for (int i = 0; i < min; i++) {
233       char x = a.charAt(i);
234       char y = s2.charAt(i);
235       if (x != y) {
236         x = Character.toUpperCase(x);
237         y = Character.toUpperCase(y);
238         if (x != y) {
239           x = Character.toLowerCase(x);
240           y = Character.toLowerCase(y);
241           if (x != y) { return x - y; }
242         }
243       }
244     }
245     return n1 - n2;
246   }
247
248   @MJI
249   public boolean regionMatches__ILjava_lang_String_2II__Z (MJIEnv env, int objRef, int toffset, int otherRef, int ooffset, int len) {
250     String obj = env.getStringObject(objRef);
251     String other = env.getStringObject(otherRef);
252     return obj.regionMatches(toffset, other, ooffset, len);
253
254   }
255
256   @MJI
257   public boolean regionMatches__ZILjava_lang_String_2II__Z (MJIEnv env, int objRef, boolean ignoreCase, int toffset, int otherRef, int ooffset, int len) {
258     String obj = env.getStringObject(objRef);
259     String other = env.getStringObject(otherRef);
260     return obj.regionMatches(ignoreCase, toffset, other, ooffset, len);
261
262   }
263
264   @MJI
265   public boolean startsWith__Ljava_lang_String_2I__Z (MJIEnv env, int objRef, int prefixRef, int toffset) {
266     String thisStr = env.getStringObject(objRef);
267     String prefix = env.getStringObject(prefixRef);
268     return thisStr.startsWith(prefix, toffset);
269   }
270
271   @MJI
272   public boolean startsWith__Ljava_lang_String_2__Z (MJIEnv env, int objRef, int prefixRef) {
273     String thisStr = env.getStringObject(objRef);
274     String prefix = env.getStringObject(prefixRef);
275     return thisStr.startsWith(prefix);
276   }
277
278   @MJI
279   public int hashCode____I (MJIEnv env, int objref) {
280     return computeStringHashCode(env, objref);
281   }
282
283   public static int computeStringHashCode(MJIEnv env, int objref) {
284     ElementInfo ei = env.getElementInfo(objref);
285     int h = ei.getIntField("hash");
286
287     if (h == 0) {
288       int vref = env.getReferenceField(objref, "value");
289
290       // now get the char array data, but be aware they are stored as ints
291       ElementInfo eiVal = env.getElementInfo(vref);
292       char[] values = eiVal.asCharArray();
293
294       for (int i = 0; i < values.length; i++) {
295         h = 31 * h + values[i];
296       }
297
298       ei = ei.getModifiableInstance();
299       ei.setIntField("hash", h);
300     }
301
302     return h;
303   }
304
305   @MJI
306   public int indexOf__I__I (MJIEnv env, int objref, int c) {
307     return indexOf__II__I(env, objref, c, 0);
308   }
309
310   @MJI
311   public int indexOf__II__I (MJIEnv env, int objref, int c, int fromIndex) {
312     int vref = env.getReferenceField(objref, "value");
313     ElementInfo ei = env.getElementInfo(vref);
314     char[] values = ((CharArrayFields) ei.getFields()).asCharArray();
315
316     int len = values.length;
317
318     if (fromIndex >= len) { return -1; }
319     if (fromIndex < 0) {
320       fromIndex = 0;
321     }
322
323     for (int i = fromIndex; i < len; i++) {
324       if (values[i] == c) { return i; }
325     }
326
327     return -1;
328   }
329
330   @MJI
331   public int lastIndexOf__I__I (MJIEnv env, int objref, int c) {
332     return lastIndexOf__II__I(env, objref, c, Integer.MAX_VALUE);
333   }
334
335   @MJI
336   public int lastIndexOf__II__I (MJIEnv env, int objref, int c, int fromIndex) {
337     int vref = env.getReferenceField(objref, "value");
338     ElementInfo ei = env.getElementInfo(vref);
339     char[] values = ((CharArrayFields) ei.getFields()).asCharArray();
340
341     int len = values.length;
342
343     if (fromIndex < 0) { return -1; }
344     if (fromIndex > len - 1) {
345       fromIndex = len - 1;
346     }
347
348     for (int i = fromIndex; i >= 0; i--) {
349       if (values[i] == c) { return i; }
350     }
351
352     return -1;
353   }
354
355   @MJI
356   public int indexOf__Ljava_lang_String_2__I (MJIEnv env, int objref, int str) {
357     String thisStr = env.getStringObject(objref);
358     String indexStr = env.getStringObject(str);
359
360     return thisStr.indexOf(indexStr);
361   }
362
363   @MJI
364   public int indexOf__Ljava_lang_String_2I__I (MJIEnv env, int objref, int str, int fromIndex) {
365     String thisStr = env.getStringObject(objref);
366     String indexStr = env.getStringObject(str);
367
368     return thisStr.indexOf(indexStr, fromIndex);
369   }
370
371   @MJI
372   public int lastIndexOf__Ljava_lang_String_2I__I (MJIEnv env, int objref, int str, int fromIndex) {
373     String thisStr = env.getStringObject(objref);
374     String indexStr = env.getStringObject(str);
375
376     return thisStr.lastIndexOf(indexStr, fromIndex);
377   }
378
379   @MJI
380   public int substring__I__Ljava_lang_String_2 (MJIEnv env, int objRef, int beginIndex) {
381     String obj = env.getStringObject(objRef);
382     return substring__II__Ljava_lang_String_2(env, objRef, beginIndex, obj.length());
383   }
384
385   @MJI
386   public int substring__II__Ljava_lang_String_2 (MJIEnv env, int objRef, int beginIndex, int endIndex) {
387     if (beginIndex > endIndex) {
388       env.throwException(sioobe, sioor + (endIndex - beginIndex));
389       return 0;
390     }
391     if (beginIndex < 0) {
392       env.throwException(sioobe, sioor + beginIndex);
393       return 0;
394     }
395     String obj = env.getStringObject(objRef);
396     if (endIndex > obj.length()) {
397       env.throwException(sioobe, sioor + endIndex);
398       return 0;
399     }
400     String result = obj.substring(beginIndex, endIndex);
401     return env.newString(result);
402
403   }
404
405   @MJI
406   public int concat__Ljava_lang_String_2__Ljava_lang_String_2 (MJIEnv env, int objRef, int strRef) {
407     Heap heap = env.getHeap();
408
409     ElementInfo thisStr = heap.get(objRef);
410     CharArrayFields thisFields = (CharArrayFields) heap.get(thisStr.getReferenceField("value")).getFields();
411     char[] thisChars = thisFields.asCharArray();
412     int thisLength = thisChars.length;
413
414     ElementInfo otherStr = heap.get(strRef);
415     CharArrayFields otherFields = (CharArrayFields) heap.get(otherStr.getReferenceField("value")).getFields();
416     char[] otherChars = otherFields.asCharArray();
417     int otherLength = otherChars.length;
418
419     if (otherLength == 0) { return objRef; }
420
421     char resultChars[] = new char[thisLength + otherLength];
422     System.arraycopy(thisChars, 0, resultChars, 0, thisLength);
423     System.arraycopy(otherChars, 0, resultChars, thisLength, otherLength);
424
425     return env.newString(new String(resultChars));
426   }
427
428   // --- the various replaces
429
430   @MJI
431   public int replace__CC__Ljava_lang_String_2 (MJIEnv env, int objRef, char oldChar, char newChar) {
432
433     if (oldChar == newChar) { // nothing to replace
434       return objRef;
435     }
436
437     int vref = env.getReferenceField(objRef, "value");
438     ElementInfo ei = env.getModifiableElementInfo(vref);
439     char[] values = ((CharArrayFields) ei.getFields()).asCharArray();
440     int len = values.length;
441
442     char[] newValues = null;
443
444     for (int i = 0, j = 0; j < len; i++, j++) {
445       char c = values[i];
446       if (c == oldChar) {
447         if (newValues == null) {
448           newValues = new char[len];
449           if (j > 0) {
450             System.arraycopy(values, 0, newValues, 0, j);
451           }
452         }
453         newValues[j] = newChar;
454       } else {
455         if (newValues != null) {
456           newValues[j] = c;
457         }
458       }
459     }
460
461     if (newValues != null) {
462       String s = new String(newValues);
463       return env.newString(s);
464
465     } else { // oldChar not found, return the original string
466       return objRef;
467     }
468   }
469
470   @MJI
471   public boolean matches__Ljava_lang_String_2__Z (MJIEnv env, int objRef, int regexRef) {
472     String s = env.getStringObject(objRef);
473     String r = env.getStringObject(regexRef);
474
475     return s.matches(r);
476   }
477
478   @MJI
479   public int replaceFirst__Ljava_lang_String_2Ljava_lang_String_2__Ljava_lang_String_2 (MJIEnv env, int objRef, int regexRef, int replacementRef) {
480     String thisStr = env.getStringObject(objRef);
481     String regexStr = env.getStringObject(regexRef);
482     String replacementStr = env.getStringObject(replacementRef);
483
484     String result = thisStr.replaceFirst(regexStr, replacementStr);
485     return (result != thisStr) ? env.newString(result) : objRef;
486   }
487
488   @MJI
489   public int replaceAll__Ljava_lang_String_2Ljava_lang_String_2__Ljava_lang_String_2 (MJIEnv env, int objRef, int regexRef, int replacementRef) {
490     String thisStr = env.getStringObject(objRef);
491     String regexStr = env.getStringObject(regexRef);
492     String replacementStr = env.getStringObject(replacementRef);
493
494     String result = thisStr.replaceAll(regexStr, replacementStr);
495     return (result != thisStr) ? env.newString(result) : objRef;
496   }
497
498   @MJI
499   public int split__Ljava_lang_String_2I___3Ljava_lang_String_2 (MJIEnv env, int clsObjRef, int strRef, int limit) {
500     String s = env.getStringObject(strRef);
501     String obj = env.getStringObject(clsObjRef);
502
503     String[] result = obj.split(s, limit);
504
505     return env.newStringArray(result);
506   }
507
508   @MJI
509   public int split__Ljava_lang_String_2___3Ljava_lang_String_2 (MJIEnv env, int clsObjRef, int strRef) {
510     String s = env.getStringObject(strRef);
511     String obj = env.getStringObject(clsObjRef);
512
513     String[] result = obj.split(s);
514
515     return env.newStringArray(result);
516   }
517
518   @MJI
519   public int toLowerCase__Ljava_util_Locale_2__Ljava_lang_String_2 (MJIEnv env, int objRef, int locRef) {
520     String s = env.getStringObject(objRef);
521     Locale loc = JPF_java_util_Locale.getLocale(env, locRef);
522
523     String lower = s.toLowerCase(loc);
524
525     return (s == lower) ? objRef : env.newString(lower);
526   }
527
528   @MJI
529   public int toLowerCase____Ljava_lang_String_2 (MJIEnv env, int objRef) {
530     String s = env.getStringObject(objRef);
531     String lower = s.toLowerCase();
532
533     return (s == lower) ? objRef : env.newString(lower);
534   }
535
536   @MJI
537   public int toUpperCase__Ljava_util_Locale_2__Ljava_lang_String_2 (MJIEnv env, int objRef, int locRef) {
538     String s = env.getStringObject(objRef);
539     Locale loc = JPF_java_util_Locale.getLocale(env, locRef);
540
541     String upper = s.toUpperCase(loc);
542
543     return (s == upper) ? objRef : env.newString(upper);
544   }
545
546   @MJI
547   public int toUpperCase____Ljava_lang_String_2 (MJIEnv env, int objRef) {
548     String s = env.getStringObject(objRef);
549     String upper = s.toUpperCase();
550
551     return (s == upper) ? objRef : env.newString(upper);
552   }
553
554   @MJI
555   public int trim____Ljava_lang_String_2 (MJIEnv env, int objRef) {
556     Heap heap = env.getHeap();
557     ElementInfo thisStr = heap.get(objRef);
558
559     CharArrayFields thisFields = (CharArrayFields) heap.get(thisStr.getReferenceField("value")).getFields();
560     char[] thisChars = thisFields.asCharArray();
561     int thisLength = thisChars.length;
562
563     int start = 0;
564     int end = thisLength;
565
566     while ((start < end) && (thisChars[start] <= ' ')) {
567       start++;
568     }
569
570     while ((start < end) && (thisChars[end - 1] <= ' ')) {
571       end--;
572     }
573
574     if (start == 0 && end == thisLength) {
575       // if there was no white space, return the string itself
576       return objRef;
577     }
578
579     String result = new String(thisChars, start, end - start);
580     return env.newString(result);
581   }
582
583   @MJI
584   public int toCharArray_____3C (MJIEnv env, int objref) {
585     int vref = env.getReferenceField(objref, "value");
586     char[] v = env.getCharArrayObject(vref);
587
588     int cref = env.newCharArray(v);
589
590     return cref;
591   }
592
593   @MJI
594   public int format__Ljava_lang_String_2_3Ljava_lang_Object_2__Ljava_lang_String_2 (MJIEnv env, int clsObjRef, int fmtRef, int argRef) {
595     return env.newString(env.format(fmtRef, argRef));
596   }
597
598   @MJI
599   public int format__Ljava_util_Locale_2Ljava_lang_String_2_3Ljava_lang_Object_2__Ljava_lang_String_2 (MJIEnv env, int clsObjRef, int locRef, int fmtRef, int argRef) {
600     Locale loc = JPF_java_util_Locale.getLocale(env, locRef);
601     return env.newString(env.format(loc, fmtRef, argRef));
602   }
603
604   @MJI
605   public int intern____Ljava_lang_String_2 (MJIEnv env, int robj) {
606     // <2do> Replace this with a JPF space HashSet once we have a String model
607     Heap heap = env.getHeap();
608
609     String s = env.getStringObject(robj);
610     ElementInfo ei = heap.newInternString(s, env.getThreadInfo());
611
612     return ei.getObjectRef();
613   }
614
615   @MJI
616   public int valueOf__I__Ljava_lang_String_2 (MJIEnv env, int clsref, int i) {
617     String result = String.valueOf(i);
618     return env.newString(result);
619   }
620
621   @MJI
622   public int valueOf__J__Ljava_lang_String_2 (MJIEnv env, int clsref, long l) {
623     String result = String.valueOf(l);
624     return env.newString(result);
625   }
626
627   @MJI
628   public int valueOf__F__Ljava_lang_String_2 (MJIEnv env, int clsref, float f) {
629     String result = String.valueOf(f);
630     return env.newString(result);
631   }
632
633   @MJI
634   public int valueOf__D__Ljava_lang_String_2 (MJIEnv env, int clsref, double d) {
635     String result = String.valueOf(d);
636     return env.newString(result);
637   }
638 }