Initial revision
[gcc.git] / libjava / java / lang / natString.cc
1 // natString.cc - Implementation of java.lang.String native methods.
2
3 /* Copyright (C) 1998, 1999 Cygnus Solutions
4
5 This file is part of libgcj.
6
7 This software is copyrighted work licensed under the terms of the
8 Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
9 details. */
10
11 #include <config.h>
12
13 #include <string.h>
14 #include <stdlib.h>
15
16 #include <cni.h>
17 #include <java/lang/Character.h>
18 #include <java/lang/String.h>
19 #include <java/lang/IndexOutOfBoundsException.h>
20 #include <java/lang/ArrayIndexOutOfBoundsException.h>
21 #include <java/lang/StringIndexOutOfBoundsException.h>
22 #include <java/lang/NullPointerException.h>
23 #include <java/io/ByteArrayOutputStream.h>
24 #include <java/io/OutputStreamWriter.h>
25 #include <java/io/ByteArrayInputStream.h>
26 #include <java/io/InputStreamReader.h>
27 #include <jvm.h>
28
29 static jstring* strhash = NULL;
30 static int strhash_count = 0; /* Number of slots used in strhash. */
31 static int strhash_size = 0; /* Number of slots available in strhash.
32 * Assumed be power of 2! */
33
34 #define DELETED_STRING ((jstring)(~0))
35 #define SET_STRING_IS_INTERNED(STR) /* nothing */
36
37 /* Find a slot where the string with elements DATA, length LEN,
38 and hash HASH should go in the strhash table of interned strings. */
39 jstring*
40 _Jv_StringFindSlot (jchar* data, jint len, jint hash)
41 {
42 JvSynchronize sync (&StringClass);
43
44 int start_index = hash & (strhash_size - 1);
45 int deleted_index = -1;
46
47 register int index = start_index;
48 /* step must be non-zero, and relatively prime with strhash_size. */
49 int step = 8 * hash + 7;
50 for (;;)
51 {
52 register jstring* ptr = &strhash[index];
53 if (*ptr == NULL)
54 {
55 if (deleted_index >= 0)
56 return (&strhash[deleted_index]);
57 else
58 return ptr;
59 }
60 else if (*ptr == DELETED_STRING)
61 deleted_index = index;
62 else if ((*ptr)->length() == len
63 && memcmp(JvGetStringChars(*ptr), data, 2*len) == 0)
64 return (ptr);
65 index = (index + step) & (strhash_size - 1);
66 JvAssert (index != start_index);
67 }
68 }
69
70 /* Calculate a hash code for the string starting at PTR at given LENGTH.
71 This uses the same formula as specified for java.lang.String.hash. */
72
73 static jint
74 hashChars (jchar* ptr, jint length)
75 {
76 register jchar* limit = ptr + length;
77 jint hash = 0;
78 // Updated specification from
79 // http://www.javasoft.com/docs/books/jls/clarify.html.
80 while (ptr < limit)
81 hash = (31 * hash) + *ptr++;
82 return hash;
83 }
84
85 jint
86 java::lang::String::hashCode()
87 {
88 return hashChars(JvGetStringChars(this), length());
89 }
90
91 jstring*
92 _Jv_StringGetSlot (jstring str)
93 {
94 jchar* data = JvGetStringChars(str);
95 int length = str->length();
96 return _Jv_StringFindSlot(data, length, hashChars (data, length));
97 }
98
99 void
100 java::lang::String::rehash()
101 {
102 JvSynchronize sync (&StringClass);
103
104 if (strhash == NULL)
105 {
106 strhash_size = 1024;
107 strhash = (jstring *) _Jv_AllocBytes (strhash_size * sizeof (jstring));
108 memset (strhash, 0, strhash_size * sizeof (jstring));
109 }
110 else
111 {
112 register int i = strhash_size;
113 register jstring* ptr = strhash + i;
114 strhash_size *= 2;
115 strhash = (jstring *) _Jv_AllocBytes (strhash_size * sizeof (jstring));
116 memset (strhash, 0, strhash_size * sizeof (jstring));
117
118 while (--i >= 0)
119 {
120 --ptr;
121 if (*ptr == NULL || *ptr == DELETED_STRING)
122 continue;
123
124 /* This is faster equivalent of
125 * *__JvGetInternSlot(*ptr) = *ptr; */
126 jint hash = (*ptr)->hashCode();
127 jint index = hash & (strhash_size - 1);
128 jint step = 8 * hash + 7;
129 for (;;)
130 {
131 if (strhash[index] == NULL)
132 {
133 strhash[index] = *ptr;
134 break;
135 }
136 index = (index + step) & (strhash_size - 1);
137 }
138 }
139 }
140 }
141
142 jstring
143 java::lang::String::intern()
144 {
145 JvSynchronize sync (&StringClass);
146 if (4 * strhash_count >= 3 * strhash_size)
147 rehash();
148 jstring* ptr = _Jv_StringGetSlot(this);
149 if (*ptr != NULL && *ptr != DELETED_STRING)
150 return *ptr;
151 SET_STRING_IS_INTERNED(this);
152 strhash_count++;
153 *ptr = this;
154 return this;
155 }
156
157 /* Called by String fake finalizer. */
158 void
159 java::lang::String::unintern()
160 {
161 JvSynchronize sync (&StringClass);
162 jstring* ptr = _Jv_StringGetSlot(this);
163 if (*ptr == NULL || *ptr == DELETED_STRING)
164 return;
165 *ptr = DELETED_STRING;
166 strhash_count--;
167 }
168
169 jstring
170 _Jv_NewStringUTF (const char *bytes)
171 {
172 int size = strlen (bytes);
173 unsigned char *p = (unsigned char *) bytes;
174
175 int length = _Jv_strLengthUtf8 ((char *) p, size);
176 if (length < 0)
177 return NULL;
178
179 jstring jstr = JvAllocString (length);
180 jchar *chrs = JvGetStringChars (jstr);
181
182 p = (unsigned char *) bytes;
183 unsigned char *limit = p + size;
184 while (p < limit)
185 *chrs++ = UTF8_GET (p, limit);
186
187 return jstr;
188 }
189
190 jstring
191 _Jv_NewStringUtf8Const (Utf8Const* str)
192 {
193 jchar *chrs;
194 jchar buffer[100];
195 jstring jstr;
196 register unsigned char* data = (unsigned char*) str->data;
197 register unsigned char* limit = data + str->length;
198 int length = _Jv_strLengthUtf8(str->data, str->length);
199
200 if (length <= (int) (sizeof(buffer) / sizeof(jchar)))
201 {
202 jstr = NULL;
203 chrs = buffer;
204 }
205 else
206 {
207 jstr = JvAllocString(length);
208 chrs = JvGetStringChars(jstr);
209 }
210
211 while (data < limit)
212 *chrs++ = UTF8_GET(data, limit);
213 chrs -= length;
214
215 JvSynchronize sync (&StringClass);
216 if (4 * strhash_count >= 3 * strhash_size)
217 java::lang::String::rehash();
218 int hash = str->hash;
219 jstring* ptr = _Jv_StringFindSlot (chrs, length, hash);
220 if (*ptr != NULL && *ptr != DELETED_STRING)
221 return *ptr;
222 strhash_count++;
223 if (jstr == NULL)
224 {
225 jstr = JvAllocString(length);
226 chrs = JvGetStringChars(jstr);
227 memcpy (chrs, buffer, sizeof(jchar)*length);
228 }
229 *ptr = jstr;
230 SET_STRING_IS_INTERNED(jstr);
231 return jstr;
232 }
233
234 jsize
235 _Jv_GetStringUTFLength (jstring string)
236 {
237 register jsize len = 0;
238 register jchar *ptr = JvGetStringChars (string);
239 register jsize i = string->length();
240 while (--i >= 0)
241 {
242 register jchar ch = *ptr++;
243 if (ch > 0 && ch <= 0x7F)
244 len += 1;
245 else if (ch <= 0x7FF)
246 len += 2;
247 else
248 len += 3;
249 }
250 return len;
251 }
252
253 // Not sure this quite matches GetStringUTFRegion.
254 // null-termination of result? len? throw exception?
255 jsize
256 _Jv_GetStringUTFRegion (jstring str, jsize start, jsize len, char *buf)
257 {
258 register jchar *sptr = JvGetStringChars (str) + start;
259 register jsize i = len;
260 register char *dptr = buf;
261 while (--i >= 0)
262 {
263 jchar ch = *sptr++;
264 if (ch > 0 && ch <= 0x7F)
265 *dptr++ = (char) ch;
266 else if (ch <= 0x7FF)
267 {
268 *dptr++ = (char) (0xC0 + ((ch >> 6) & 0x1F));
269 *dptr++ = (char) (0x80 + (ch & 0x3F));
270 }
271 else
272 {
273 *dptr++ = (char) (0xE0 + ((ch >> 12) & 0xF));
274 *dptr++ = (char) (0x80 + ((ch >> 6) & 0x3F));
275 *dptr++ = (char) (0x80 + (ch & 0x3F));
276 }
277 }
278 return dptr - buf;
279 }
280
281 jstring
282 _Jv_AllocString(jsize len)
283 {
284 jsize sz = sizeof(java::lang::String) + len * sizeof(jchar);
285
286 jstring obj = (jstring) JvAllocObject(&StringClass, sz);
287
288 obj->data = obj;
289 obj->boffset = sizeof(java::lang::String);
290 obj->count = len;
291 return obj;
292 }
293
294 jstring
295 _Jv_NewString(const jchar *chars, jsize len)
296 {
297 jstring str = _Jv_AllocString(len);
298 jchar* data = JvGetStringChars (str);
299 while (--len >= 0)
300 *data++ = *chars++;
301 return str;
302 }
303
304 jstring
305 _Jv_NewStringLatin1(const char *bytes, jsize len)
306 {
307 jstring str = JvAllocString(len);
308 jchar* data = JvGetStringChars (str);
309 while (--len >= 0)
310 *data++ = *(unsigned char*)bytes++;
311 return str;
312 }
313
314 void
315 java::lang::String::init ()
316 {
317 count = 0;
318 boffset = sizeof(java::lang::String);
319 data = this;
320 }
321
322 void
323 java::lang::String::init(jcharArray chars, jint offset, jint count,
324 jboolean dont_copy)
325 {
326 if (! chars)
327 JvThrow (new NullPointerException);
328 jsize data_size = JvGetArrayLength (chars);
329 if (offset < 0 || count < 0 || offset + count > data_size)
330 JvThrow (new StringIndexOutOfBoundsException());
331 jcharArray array;
332 jchar *pdst;
333 if (! dont_copy)
334 {
335 array = JvNewCharArray(count);
336 pdst = elements (array);
337 memcpy (pdst, elements (chars) + offset, count * sizeof (jchar));
338 }
339 else
340 {
341 JvAssert (offset == 0);
342 array = chars;
343 pdst = elements (array);
344 }
345
346 data = array;
347 boffset = (char *) pdst - (char *) array;
348 this->count = count;
349 }
350
351 void
352 java::lang::String::init(jbyteArray ascii, jint hibyte, jint offset,
353 jint count)
354 {
355 if (! ascii)
356 JvThrow (new NullPointerException);
357 jsize data_size = JvGetArrayLength (ascii);
358 if (offset < 0 || count < 0 || offset + count < 0
359 || offset + count > data_size)
360 JvThrow (new java::lang::StringIndexOutOfBoundsException());
361 jcharArray array = JvNewCharArray(count);
362 jbyte *psrc = elements (ascii) + offset;
363 jchar *pdst = elements (array);
364 data = array;
365 boffset = (char *) pdst - (char *) array;
366 this->count = count;
367 hibyte = (hibyte & 0xff) << 8;
368 while (-- count >= 0)
369 {
370 *pdst++ = hibyte | (*psrc++ & 0xff);
371 }
372 }
373
374 void
375 java::lang::String::init (jbyteArray bytes, jint offset, jint count,
376 jstring encoding)
377 {
378 if (! bytes)
379 JvThrow (new NullPointerException);
380 jsize data_size = JvGetArrayLength (bytes);
381 if (offset < 0 || count < 0 || offset + count < 0
382 || offset + count > data_size)
383 JvThrow (new StringIndexOutOfBoundsException);
384
385 java::io::ByteArrayInputStream *b
386 = new java::io::ByteArrayInputStream (bytes, offset, count);
387 java::io::InputStreamReader *ir
388 = new java::io::InputStreamReader (b, encoding);
389 // FIXME: we allocate too much here in some cases.
390 jcharArray array = JvNewCharArray (count);
391 data = array;
392 boffset = (char *) elements (array) - (char *) array;
393 // FIXME: this can throw IOException.
394 this->count = ir->read(array, 0, count);
395 }
396
397 jboolean
398 java::lang::String::equals(jobject anObject)
399 {
400 if (anObject == NULL)
401 return false;
402 if (anObject == this)
403 return true;
404 if (anObject->getClass() != &StringClass)
405 return false;
406 jstring other = (jstring) anObject;
407 if (count != other->count)
408 return false;
409 /* if both are interned, return false. */
410 register jint i = count;
411 register jchar *xptr = JvGetStringChars (this);
412 register jchar *yptr = JvGetStringChars (other);
413 while (--i >= 0)
414 {
415 if (*xptr++ != *yptr++)
416 return false;
417 }
418 return true;
419 }
420
421 jchar
422 java::lang::String::charAt(jint i)
423 {
424 if (i < 0 || i >= count)
425 JvThrow (new java::lang::StringIndexOutOfBoundsException());
426 return JvGetStringChars(this)[i];
427 }
428
429 void
430 java::lang::String::getChars(jint srcBegin, jint srcEnd,
431 jcharArray dst, jint dstBegin)
432 {
433 jint dst_length = JvGetArrayLength (dst);
434 if (srcBegin < 0 || srcBegin > srcEnd || srcEnd > count
435 || dstBegin < 0 || dstBegin + (srcEnd-srcBegin) > dst_length)
436 JvThrow (new java::lang::ArrayIndexOutOfBoundsException());
437 register jchar *dPtr = elements (dst) + dstBegin;
438 register jchar *sPtr = JvGetStringChars (this) + srcBegin;
439 register jint i = srcEnd-srcBegin;
440 while (--i >= 0)
441 *dPtr++ = *sPtr++;
442 }
443
444 jbyteArray
445 java::lang::String::getBytes (jstring enc)
446 {
447 java::io::ByteArrayOutputStream *os
448 = new java::io::ByteArrayOutputStream(length ());
449 java::io::OutputStreamWriter *ow
450 = new java::io::OutputStreamWriter(os, enc);
451
452 ow->write(this, 0, length ());
453 ow->flush();
454
455 return os->toByteArray();
456 }
457
458 void
459 java::lang::String::getBytes(jint srcBegin, jint srcEnd,
460 jbyteArray dst, jint dstBegin)
461 {
462 jint dst_length = JvGetArrayLength (dst);
463 if (srcBegin < 0 || srcBegin > srcEnd || srcEnd > count
464 || dstBegin < 0 || dstBegin + (srcEnd-srcBegin) > dst_length)
465 JvThrow (new java::lang::ArrayIndexOutOfBoundsException());
466 register jbyte *dPtr = elements (dst) + dstBegin;
467 register jchar *sPtr = JvGetStringChars (this) + srcBegin;
468 register jint i = srcEnd-srcBegin;
469 while (--i >= 0)
470 *dPtr++ = (jbyte) *sPtr++;
471 }
472
473 jcharArray
474 java::lang::String::toCharArray()
475 {
476 jcharArray array = JvNewCharArray(count);
477 register jchar *dPtr = elements (array);
478 register jchar *sPtr = JvGetStringChars (this);
479 register jint i = count;
480 while (--i >= 0)
481 *dPtr++ = *sPtr++;
482 return array;
483 }
484
485 jboolean
486 java::lang::String::equalsIgnoreCase (jstring anotherString)
487 {
488 if (count != anotherString->count)
489 return false;
490 register jchar *tptr = JvGetStringChars (this);
491 register jchar *optr = JvGetStringChars (anotherString);
492 register jint i = count;
493 while (--i >= 0)
494 {
495 jchar tch = *tptr++;
496 jchar och = *optr++;
497 if (tch != och
498 && (java::lang::Character::toLowerCase (tch)
499 != java::lang::Character::toLowerCase (och))
500 && (java::lang::Character::toUpperCase (tch)
501 != java::lang::Character::toUpperCase (och)))
502 return false;
503 }
504 return true;
505 }
506
507 jboolean
508 java::lang::String::regionMatches (jint toffset,
509 jstring other, jint ooffset, jint len)
510 {
511 if (toffset < 0 || ooffset < 0
512 || toffset + len > count
513 || ooffset + len > other->count)
514 return false;
515 register jchar *tptr = JvGetStringChars (this) + toffset;
516 register jchar *optr = JvGetStringChars (other) + ooffset;
517 register jint i = len;
518 while (--i >= 0)
519 {
520 if (*tptr++ != *optr++)
521 return false;
522 }
523 return true;
524 }
525
526 jint
527 java::lang::String::compareTo (jstring anotherString)
528 {
529 register jchar *tptr = JvGetStringChars (this);
530 register jchar *optr = JvGetStringChars (anotherString);
531 jint tlen = this->count;
532 jint olen = anotherString->count;
533 register jint i = tlen > olen ? olen : tlen;
534 while (--i >= 0)
535 {
536 jchar tch = *tptr++;
537 jchar och = *optr++;
538 if (tch != och)
539 return (jint) tch - (jint) och;
540 }
541 return tlen - olen;
542 }
543
544 jboolean
545 java::lang::String::regionMatches (jboolean ignoreCase, jint toffset,
546 jstring other, jint ooffset, jint len)
547 {
548 if (toffset < 0 || ooffset < 0
549 || toffset + len > count
550 || ooffset + len > other->count)
551 return false;
552 register jchar *tptr = JvGetStringChars (this) + toffset;
553 register jchar *optr = JvGetStringChars (other) + ooffset;
554 register jint i = len;
555 while (--i >= 0)
556 {
557 jchar tch = *tptr++;
558 jchar och = *optr++;
559 if (tch != och)
560 return false;
561 if (ignoreCase
562 && (java::lang::Character::toLowerCase (tch)
563 != java::lang::Character::toLowerCase (och))
564 && (java::lang::Character::toUpperCase (tch)
565 != java::lang::Character::toUpperCase (och)))
566 return false;
567 }
568 return true;
569 }
570
571 jboolean
572 java::lang::String::startsWith (jstring prefix, jint toffset)
573 {
574 register jint i = prefix->count;
575 if (toffset < 0 || toffset + i > count)
576 return false;
577 register jchar *xptr = JvGetStringChars (this) + toffset;
578 register jchar *yptr = JvGetStringChars (prefix);
579 while (--i >= 0)
580 {
581 if (*xptr++ != *yptr++)
582 return false;
583 }
584 return true;
585 }
586
587 jint
588 java::lang::String::indexOf (jint ch, jint fromIndex)
589 {
590 if (fromIndex < 0)
591 fromIndex = 0;
592 register jchar *ptr = JvGetStringChars(this);
593 for (;; ++fromIndex)
594 {
595 if (fromIndex >= count)
596 return -1;
597 if (ptr[fromIndex] == ch)
598 return fromIndex;
599 }
600 }
601
602 jint
603 java::lang::String::indexOf (jstring s, jint fromIndex)
604 {
605 const jchar *const xchars = JvGetStringChars(s);
606 const jchar *const ychars = JvGetStringChars(this) + fromIndex;
607
608 const int xlength = s->length ();
609 const int ylength = length () - fromIndex;
610
611 int i = 0;
612 int j = 0;
613
614 while (i < ylength && j < xlength)
615 {
616 if (xchars[j] != ychars[i])
617 {
618 i = i - j + 1;
619 j = 0;
620 }
621 else
622 i++, j++;
623 }
624
625 if (j >= xlength)
626 return fromIndex + i - xlength;
627 else
628 return -1;
629 }
630
631 jint
632 java::lang::String::lastIndexOf (jint ch, jint fromIndex)
633 {
634 if (fromIndex >= count)
635 fromIndex = count - 1;
636 register jchar *ptr = JvGetStringChars(this);
637 for (;; --fromIndex)
638 {
639 if (fromIndex < 0)
640 return -1;
641 if (ptr[fromIndex] == ch)
642 return fromIndex;
643 }
644 }
645
646 jstring
647 java::lang::String::substring (jint beginIndex, jint endIndex)
648 {
649 if (beginIndex < 0 || endIndex > count || beginIndex > endIndex)
650 JvThrow (new StringIndexOutOfBoundsException());
651 jint newCount = endIndex - beginIndex;
652 if (newCount <= 8) // Optimization, mainly for GC.
653 return JvNewString(JvGetStringChars(this) + beginIndex, newCount);
654 jstring s = new String();
655 s->data = data;
656 s->count = newCount;
657 s->boffset = boffset + sizeof(jchar) * beginIndex;
658 return s;
659 }
660
661 jstring
662 java::lang::String::concat(jstring str)
663 {
664 jint str_count = str->count;
665 if (str_count == 0)
666 return this;
667 jstring result = JvAllocString(count + str_count);
668 register jchar *dstPtr = JvGetStringChars(result);
669 register jchar *srcPtr = JvGetStringChars(this);
670 register jint i = count;
671 while (--i >= 0)
672 *dstPtr++ = *srcPtr++;
673 srcPtr = JvGetStringChars(str);
674 i = str->count;
675 while (--i >= 0)
676 *dstPtr++ = *srcPtr++;
677 return result;
678 }
679
680 jstring
681 java::lang::String::replace (jchar oldChar, jchar newChar)
682 {
683 jint i;
684 jchar* chrs = JvGetStringChars (this);
685 for (i = 0; ; i++)
686 {
687 if (i == count)
688 return this;
689 if (chrs[i] == oldChar)
690 break;
691 }
692 jstring result = JvAllocString (count);
693 jchar *dPtr = JvGetStringChars (result);
694 for (int j = 0; j < i; j++)
695 *dPtr++ = chrs[j];
696 for (; i < count; i++)
697 {
698 jchar ch = chrs[i];
699 if (ch == oldChar)
700 ch = newChar;
701 *dPtr++ = ch;
702 }
703 return result;
704 }
705
706 jstring
707 java::lang::String::toLowerCase ()
708 {
709 jint i;
710 jchar* chrs = JvGetStringChars(this);
711 jchar ch;
712 for (i = 0; ; i++)
713 {
714 if (i == count)
715 return this;
716 jchar origChar = chrs[i];
717 ch = java::lang::Character::toLowerCase(origChar);
718 if (ch != origChar)
719 break;
720 }
721 jstring result = JvAllocString(count);
722 jchar *dPtr = JvGetStringChars (result);
723 for (int j = 0; j < i; j++)
724 *dPtr++ = chrs[j];
725 *dPtr++ = ch; i++;
726 for (; i < count; i++)
727 {
728 *dPtr++ = java::lang::Character::toLowerCase(chrs[i]);
729 }
730 return result;
731 }
732
733 jstring
734 java::lang::String::toUpperCase ()
735 {
736 jint i;
737 jchar* chrs = JvGetStringChars(this);
738 jchar ch;
739 for (i = 0; ; i++)
740 {
741 if (i == count)
742 return this;
743 jchar origChar = chrs[i];
744 ch = java::lang::Character::toUpperCase(origChar);
745 if (ch != origChar)
746 break;
747 }
748 jstring result = JvAllocString(count);
749 jchar *dPtr = JvGetStringChars (result);
750 for (int j = 0; j < i; j++)
751 *dPtr++ = chrs[j];
752 *dPtr++ = ch; i++;
753 for (; i < count; i++)
754 {
755 *dPtr++ = java::lang::Character::toUpperCase(chrs[i]);
756 }
757 return result;
758 }
759
760 jstring
761 java::lang::String::trim ()
762 {
763 jchar* chrs = JvGetStringChars(this);
764 if (count == 0 || (chrs[0] > ' ' && chrs[count-1] > ' '))
765 return this;
766 jint preTrim = 0;
767 for (;; preTrim++)
768 {
769 if (preTrim == count)
770 return new String();
771 if (chrs[preTrim] > ' ')
772 break;
773 }
774 jint endTrim = count;
775 while (chrs[endTrim-1] <= ' ')
776 endTrim--;
777 return substring(preTrim, endTrim);
778 }
779
780 jstring
781 java::lang::String::valueOf(jcharArray data, jint offset, jint count)
782 {
783 jint data_length = JvGetArrayLength (data);
784 if (offset < 0 || count < 0 || offset+count > data_length)
785 JvThrow (new java::lang::IndexOutOfBoundsException());
786 register jstring result = JvAllocString(count);
787 register jchar *sPtr = elements (data) + offset;
788 register jchar *dPtr = JvGetStringChars(result);
789 while (--count >= 0)
790 *dPtr++ = *sPtr++;
791 return result;
792 }
793
794 jstring
795 java::lang::String::valueOf(jchar c)
796 {
797 register jstring result = JvAllocString(1);
798 JvGetStringChars (result)[0] = c;
799 return result;
800 }