📄 natstring.cc
字号:
// natString.cc - Implementation of java.lang.String native methods./* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation This file is part of libgcj.This software is copyrighted work licensed under the terms of theLibgcj License. Please consult the file "LIBGCJ_LICENSE" fordetails. */#include <config.h>#include <string.h>#include <stdlib.h>#include <gcj/cni.h>#include <java/lang/Character.h>#include <java/lang/CharSequence.h>#include <java/lang/String.h>#include <java/lang/IndexOutOfBoundsException.h>#include <java/lang/ArrayIndexOutOfBoundsException.h>#include <java/lang/StringIndexOutOfBoundsException.h>#include <java/lang/NullPointerException.h>#include <java/lang/StringBuffer.h>#include <java/io/ByteArrayOutputStream.h>#include <java/io/OutputStreamWriter.h>#include <java/io/ByteArrayInputStream.h>#include <java/io/InputStreamReader.h>#include <java/util/Locale.h>#include <gnu/gcj/convert/UnicodeToBytes.h>#include <gnu/gcj/convert/BytesToUnicode.h>#include <gnu/gcj/runtime/StringBuffer.h>#include <jvm.h>static jstring* strhash = NULL;static int strhash_count = 0; /* Number of slots used in strhash. */static int strhash_size = 0; /* Number of slots available in strhash. * Assumed be power of 2! */// Some defines used by toUpperCase / toLowerCase.#define ESSET 0x00df#define CAPITAL_S 0x0053#define SMALL_I 0x0069#define CAPITAL_I_WITH_DOT 0x0130#define SMALL_DOTLESS_I 0x0131#define CAPITAL_I 0x0049#define DELETED_STRING ((jstring)(~0))#define SET_STRING_IS_INTERNED(STR) /* nothing */#define UNMASK_PTR(Ptr) (((unsigned long) (Ptr)) & ~0x01)#define MASK_PTR(Ptr) (((unsigned long) (Ptr)) | 0x01)#define PTR_MASKED(Ptr) (((unsigned long) (Ptr)) & 0x01)/* Find a slot where the string with elements DATA, length LEN, and hash HASH should go in the strhash table of interned strings. */jstring*_Jv_StringFindSlot (jchar* data, jint len, jint hash){ JvSynchronize sync (&java::lang::String::class$); int start_index = hash & (strhash_size - 1); int deleted_index = -1; int index = start_index; /* step must be non-zero, and relatively prime with strhash_size. */ jint step = (hash ^ (hash >> 16)) | 1; do { jstring* ptr = &strhash[index]; jstring value = (jstring) UNMASK_PTR (*ptr); if (value == NULL) { if (deleted_index >= 0) return (&strhash[deleted_index]); else return ptr; } else if (*ptr == DELETED_STRING) deleted_index = index; else if (value->length() == len && memcmp(JvGetStringChars(value), data, 2*len) == 0) return (ptr); index = (index + step) & (strhash_size - 1); } while (index != start_index); // Note that we can have INDEX == START_INDEX if the table has no // NULL entries but does have DELETED_STRING entries. JvAssert (deleted_index >= 0); return &strhash[deleted_index];}/* Calculate a hash code for the string starting at PTR at given LENGTH. This uses the same formula as specified for java.lang.String.hash. */static jinthashChars (jchar* ptr, jint length){ jchar* limit = ptr + length; jint hash = 0; // Updated specification from // http://www.javasoft.com/docs/books/jls/clarify.html. while (ptr < limit) hash = (31 * hash) + *ptr++; return hash;}jintjava::lang::String::hashCode(){ if (cachedHashCode == 0) cachedHashCode = hashChars(JvGetStringChars(this), length()); return cachedHashCode;}jstring*_Jv_StringGetSlot (jstring str){ jchar* data = JvGetStringChars(str); int length = str->length(); return _Jv_StringFindSlot(data, length, hashChars (data, length));}static voidrehash (){ JvSynchronize sync (&java::lang::String::class$); if (strhash == NULL) { strhash_size = 1024; strhash = (jstring *) _Jv_AllocBytes (strhash_size * sizeof (jstring)); } else { int i = strhash_size; jstring* ptr = strhash + i; int nsize = strhash_size * 2; jstring *next = (jstring *) _Jv_AllocBytes (nsize * sizeof (jstring)); while (--i >= 0) { --ptr; if (*ptr == NULL || *ptr == DELETED_STRING) continue; /* This is faster equivalent of * *__JvGetInternSlot(*ptr) = *ptr; */ jstring val = (jstring) UNMASK_PTR (*ptr); jint hash = val->hashCode(); jint index = hash & (nsize - 1); jint step = (hash ^ (hash >> 16)) | 1; for (;;) { if (next[index] == NULL) { next[index] = *ptr; break; } index = (index + step) & (nsize - 1); } } strhash_size = nsize; strhash = next; }}jstringjava::lang::String::intern(){ JvSynchronize sync (&java::lang::String::class$); if (3 * strhash_count >= 2 * strhash_size) rehash(); jstring* ptr = _Jv_StringGetSlot(this); if (*ptr != NULL && *ptr != DELETED_STRING) { // See description in _Jv_FinalizeString() to understand this. *ptr = (jstring) MASK_PTR (*ptr); return (jstring) UNMASK_PTR (*ptr); } jstring str = (this->data == this ? this : _Jv_NewString(JvGetStringChars(this), this->length())); SET_STRING_IS_INTERNED(str); strhash_count++; *ptr = str; // When string is GC'd, clear the slot in the hash table. _Jv_RegisterStringFinalizer (str); return str;}// The fake String finalizer. This is only used when the String has// been intern()d. However, we must check this case, as it might be// called by the Reference code for any String.void_Jv_FinalizeString (jobject obj){ JvSynchronize sync (&java::lang::String::class$); // We might not actually have intern()d any strings at all, if // we're being called from Reference. if (! strhash) return; jstring str = reinterpret_cast<jstring> (obj); jstring *ptr = _Jv_StringGetSlot(str); if (*ptr == NULL || *ptr == DELETED_STRING || (jobject) UNMASK_PTR (*ptr) != obj) return; // We assume the lowest bit of the pointer is free for our nefarious // manipulations. What we do is set it to `0' (implicitly) when // interning the String. If we subsequently re-intern the same // String, then we set the bit. When finalizing, if the bit is set // then we clear it and re-register the finalizer. We know this is // a safe approach because both intern() and _Jv_FinalizeString() // acquire the class lock; this bit can't be manipulated when the // lock is not held. So if we are finalizing and the bit is clear // then we know all references are gone and we can clear the entry // in the hash table. The naive approach of simply clearing the // pointer here fails in the case where a request to intern a new // string with the same contents is made between the time the // intern()d string is found to be unreachable and when the // finalizer is actually run. In this case we could clear a pointer // to a valid string, and future intern() calls for that particular // value would spuriously fail. if (PTR_MASKED (*ptr)) { *ptr = (jstring) UNMASK_PTR (*ptr); _Jv_RegisterStringFinalizer (obj); } else { *ptr = DELETED_STRING; strhash_count--; }}jstring_Jv_NewStringUTF (const char *bytes){ int size = strlen (bytes); unsigned char *p = (unsigned char *) bytes; int length = _Jv_strLengthUtf8 ((char *) p, size); if (length < 0) return NULL; jstring jstr = JvAllocString (length); jchar *chrs = JvGetStringChars (jstr); p = (unsigned char *) bytes; unsigned char *limit = p + size; while (p < limit) *chrs++ = UTF8_GET (p, limit); return jstr;}jstring_Jv_NewStringUtf8Const (Utf8Const* str){ jchar *chrs; jchar buffer[100]; jstring jstr; unsigned char* data = (unsigned char*) str->data; unsigned char* limit = data + str->length; int length = _Jv_strLengthUtf8(str->data, str->length); if (length <= (int) (sizeof(buffer) / sizeof(jchar))) { jstr = NULL; chrs = buffer; } else { jstr = JvAllocString(length); chrs = JvGetStringChars(jstr); } jint hash = 0; while (data < limit) { jchar ch = UTF8_GET(data, limit); hash = (31 * hash) + ch; *chrs++ = ch; } chrs -= length; JvSynchronize sync (&java::lang::String::class$); if (3 * strhash_count >= 2 * strhash_size) rehash(); jstring* ptr = _Jv_StringFindSlot (chrs, length, hash); if (*ptr != NULL && *ptr != DELETED_STRING) return (jstring) UNMASK_PTR (*ptr); strhash_count++; if (jstr == NULL) { jstr = JvAllocString(length); chrs = JvGetStringChars(jstr); memcpy (chrs, buffer, sizeof(jchar)*length); } jstr->cachedHashCode = hash; *ptr = jstr; SET_STRING_IS_INTERNED(jstr); // When string is GC'd, clear the slot in the hash table. Note that // we don't have to call _Jv_RegisterStringFinalizer here, as we // know the new object cannot be referred to by a Reference. _Jv_RegisterFinalizer ((void *) jstr, _Jv_FinalizeString); return jstr;}jsize_Jv_GetStringUTFLength (jstring string){ jsize len = 0; jchar *ptr = JvGetStringChars (string); jsize i = string->length(); while (--i >= 0) { jchar ch = *ptr++; if (ch > 0 && ch <= 0x7F) len += 1; else if (ch <= 0x7FF) len += 2; else len += 3; } return len;}// Not sure this quite matches GetStringUTFRegion.// null-termination of result? len? throw exception?jsize_Jv_GetStringUTFRegion (jstring str, jsize start, jsize len, char *buf){ jchar *sptr = JvGetStringChars (str) + start; jsize i = len; char *dptr = buf; while (--i >= 0) { jchar ch = *sptr++; if (ch > 0 && ch <= 0x7F) *dptr++ = (char) ch; else if (ch <= 0x7FF) { *dptr++ = (char) (0xC0 + ((ch >> 6) & 0x1F)); *dptr++ = (char) (0x80 + (ch & 0x3F)); } else { *dptr++ = (char) (0xE0 + ((ch >> 12) & 0xF)); *dptr++ = (char) (0x80 + ((ch >> 6) & 0x3F)); *dptr++ = (char) (0x80 + (ch & 0x3F)); } } return dptr - buf;}/* Put printed (decimal) representation of NUM in a buffer. BUFEND marks the end of the buffer, which must be at least 11 jchars long. Returns the COUNT of jchars written. The result is in (BUFEND - COUNT) (inclusive) upto (BUFEND) (exclusive). */jint_Jv_FormatInt (jchar* bufend, jint num){ register jchar* ptr = bufend; jboolean isNeg; if (num < 0) { isNeg = true; num = -(num); if (num < 0) { // Must be MIN_VALUE, so handle this special case. // FIXME use 'unsigned jint' for num. *--ptr = '8'; num = 214748364; } } else isNeg = false; do { *--ptr = (jchar) ((int) '0' + (num % 10)); num /= 10; } while (num > 0); if (isNeg) *--ptr = '-'; return bufend - ptr;}jstringjava::lang::String::valueOf (jint num){ // Use an array large enough for "-2147483648"; i.e. 11 chars. jchar buffer[11]; int i = _Jv_FormatInt (buffer+11, num); return _Jv_NewString (buffer+11-i, i);}jstring_Jv_NewString(const jchar *chars, jsize len){ jstring str = _Jv_AllocString(len); jchar* data = JvGetStringChars (str); while (--len >= 0) *data++ = *chars++; return str;}jstring_Jv_NewStringLatin1(const char *bytes, jsize len){ jstring str = JvAllocString(len); jchar* data = JvGetStringChars (str); while (--len >= 0) *data++ = *(unsigned char*)bytes++; return str;}voidjava::lang::String::init(jcharArray chars, jint offset, jint count, jboolean dont_copy){ if (! chars) throw new NullPointerException; jsize data_size = JvGetArrayLength (chars); if (offset < 0 || count < 0 || offset + count < 0 || offset + count > data_size) throw new ArrayIndexOutOfBoundsException; jcharArray array; jchar *pdst; if (! dont_copy) { array = JvNewCharArray(count); pdst = elements (array); memcpy (pdst, elements (chars) + offset, count * sizeof (jchar)); } else { array = chars; pdst = &(elements(array)[offset]); } data = array; boffset = (char *) pdst - (char *) array; this->count = count;}voidjava::lang::String::init(jbyteArray ascii, jint hibyte, jint offset, jint count){ if (! ascii) throw new NullPointerException; jsize data_size = JvGetArrayLength (ascii); if (offset < 0 || count < 0 || offset + count < 0 || offset + count > data_size) throw new ArrayIndexOutOfBoundsException; jcharArray array = JvNewCharArray(count); jbyte *psrc = elements (ascii) + offset; jchar *pdst = elements (array); data = array; boffset = (char *) pdst - (char *) array; this->count = count; hibyte = (hibyte & 0xff) << 8; while (-- count >= 0) { *pdst++ = hibyte | (*psrc++ & 0xff); }}voidjava::lang::String::init (jbyteArray bytes, jint offset, jint count, jstring encoding){ if (! bytes) throw new NullPointerException; jsize data_size = JvGetArrayLength (bytes); if (offset < 0 || count < 0 || offset + count < 0 || offset + count > data_size) throw new ArrayIndexOutOfBoundsException; jcharArray array = JvNewCharArray (count); gnu::gcj::convert::BytesToUnicode *converter = gnu::gcj::convert::BytesToUnicode::getDecoder(encoding); jint outpos = 0; int avail = count; converter->setInput(bytes, offset, offset+count); while (converter->inpos < converter->inlength) { int done = converter->read(array, outpos, avail); if (done == 0) { jint new_size = 2 * (outpos + avail); jcharArray new_array = JvNewCharArray (new_size); memcpy (elements (new_array), elements (array), outpos * sizeof(jchar)); array = new_array; avail = new_size - outpos; } else { outpos += done; avail -= done; } } converter->done (); this->data = array; this->boffset = (char *) elements (array) - (char *) array; this->count = outpos;}voidjava::lang::String::init (gnu::gcj::runtime::StringBuffer *buffer){ init (buffer->value, 0, buffer->count, true);}jbooleanjava::lang::String::equals(jobject anObject){ if (anObject == NULL) return false; if (anObject == this) return true; if (anObject->getClass() != &java::lang::String::class$)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -