string.cc revision 94f7b49578b6aaa80de8ffed230648d601393905
1/* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "string-inl.h" 18 19#include "arch/memcmp16.h" 20#include "array.h" 21#include "class-inl.h" 22#include "gc/accounting/card_table-inl.h" 23#include "intern_table.h" 24#include "object-inl.h" 25#include "runtime.h" 26#include "handle_scope-inl.h" 27#include "thread.h" 28#include "utf-inl.h" 29 30namespace art { 31namespace mirror { 32 33// TODO: get global references for these 34GcRoot<Class> String::java_lang_String_; 35 36int32_t String::FastIndexOf(int32_t ch, int32_t start) { 37 int32_t count = GetLength(); 38 if (start < 0) { 39 start = 0; 40 } else if (start > count) { 41 start = count; 42 } 43 const uint16_t* chars = GetCharArray()->GetData() + GetOffset(); 44 const uint16_t* p = chars + start; 45 const uint16_t* end = chars + count; 46 while (p < end) { 47 if (*p++ == ch) { 48 return (p - 1) - chars; 49 } 50 } 51 return -1; 52} 53 54void String::SetClass(Class* java_lang_String) { 55 CHECK(java_lang_String_.IsNull()); 56 CHECK(java_lang_String != NULL); 57 java_lang_String_ = GcRoot<Class>(java_lang_String); 58} 59 60void String::ResetClass() { 61 CHECK(!java_lang_String_.IsNull()); 62 java_lang_String_ = GcRoot<Class>(nullptr); 63} 64 65int32_t String::GetHashCode() { 66 int32_t result = GetField32(OFFSET_OF_OBJECT_MEMBER(String, hash_code_)); 67 if (UNLIKELY(result == 0)) { 68 ComputeHashCode(); 69 } 70 result = GetField32(OFFSET_OF_OBJECT_MEMBER(String, hash_code_)); 71 DCHECK(result != 0 || ComputeUtf16Hash(GetCharArray(), GetOffset(), GetLength()) == 0) 72 << ToModifiedUtf8() << " " << result; 73 return result; 74} 75 76void String::ComputeHashCode() { 77 SetHashCode(ComputeUtf16Hash(GetCharArray(), GetOffset(), GetLength())); 78} 79 80int32_t String::GetUtfLength() { 81 return CountUtf8Bytes(GetCharArray()->GetData() + GetOffset(), GetLength()); 82} 83 84String* String::AllocFromUtf16(Thread* self, 85 int32_t utf16_length, 86 const uint16_t* utf16_data_in, 87 int32_t hash_code) { 88 CHECK(utf16_data_in != nullptr || utf16_length == 0); 89 String* string = Alloc(self, utf16_length); 90 if (UNLIKELY(string == nullptr)) { 91 return nullptr; 92 } 93 CharArray* array = const_cast<CharArray*>(string->GetCharArray()); 94 if (UNLIKELY(array == nullptr)) { 95 return nullptr; 96 } 97 memcpy(array->GetData(), utf16_data_in, utf16_length * sizeof(uint16_t)); 98 if (hash_code != 0) { 99 DCHECK_EQ(hash_code, ComputeUtf16Hash(utf16_data_in, utf16_length)); 100 string->SetHashCode(hash_code); 101 } else { 102 string->ComputeHashCode(); 103 } 104 return string; 105} 106 107String* String::AllocFromModifiedUtf8(Thread* self, const char* utf) { 108 DCHECK(utf != nullptr); 109 size_t char_count = CountModifiedUtf8Chars(utf); 110 return AllocFromModifiedUtf8(self, char_count, utf); 111} 112 113String* String::AllocFromModifiedUtf8(Thread* self, int32_t utf16_length, 114 const char* utf8_data_in) { 115 String* string = Alloc(self, utf16_length); 116 if (UNLIKELY(string == nullptr)) { 117 return nullptr; 118 } 119 uint16_t* utf16_data_out = 120 const_cast<uint16_t*>(string->GetCharArray()->GetData()); 121 ConvertModifiedUtf8ToUtf16(utf16_data_out, utf8_data_in); 122 string->ComputeHashCode(); 123 return string; 124} 125 126String* String::Alloc(Thread* self, int32_t utf16_length) { 127 StackHandleScope<1> hs(self); 128 Handle<CharArray> array(hs.NewHandle(CharArray::Alloc(self, utf16_length))); 129 if (UNLIKELY(array.Get() == nullptr)) { 130 return nullptr; 131 } 132 return Alloc(self, array); 133} 134 135String* String::Alloc(Thread* self, Handle<CharArray> array) { 136 // Hold reference in case AllocObject causes GC. 137 String* string = down_cast<String*>(GetJavaLangString()->AllocObject(self)); 138 if (LIKELY(string != nullptr)) { 139 string->SetArray(array.Get()); 140 string->SetCount(array->GetLength()); 141 } 142 return string; 143} 144 145bool String::Equals(String* that) { 146 if (this == that) { 147 // Quick reference equality test 148 return true; 149 } else if (that == NULL) { 150 // Null isn't an instanceof anything 151 return false; 152 } else if (this->GetLength() != that->GetLength()) { 153 // Quick length inequality test 154 return false; 155 } else { 156 // Note: don't short circuit on hash code as we're presumably here as the 157 // hash code was already equal 158 for (int32_t i = 0; i < that->GetLength(); ++i) { 159 if (this->CharAt(i) != that->CharAt(i)) { 160 return false; 161 } 162 } 163 return true; 164 } 165} 166 167bool String::Equals(const uint16_t* that_chars, int32_t that_offset, int32_t that_length) { 168 if (this->GetLength() != that_length) { 169 return false; 170 } else { 171 for (int32_t i = 0; i < that_length; ++i) { 172 if (this->CharAt(i) != that_chars[that_offset + i]) { 173 return false; 174 } 175 } 176 return true; 177 } 178} 179 180bool String::Equals(const char* modified_utf8) { 181 for (int32_t i = 0; i < GetLength(); ++i) { 182 uint16_t ch = GetUtf16FromUtf8(&modified_utf8); 183 if (ch == '\0' || ch != CharAt(i)) { 184 return false; 185 } 186 } 187 return *modified_utf8 == '\0'; 188} 189 190bool String::Equals(const StringPiece& modified_utf8) { 191 const char* p = modified_utf8.data(); 192 for (int32_t i = 0; i < GetLength(); ++i) { 193 uint16_t ch = GetUtf16FromUtf8(&p); 194 if (ch != CharAt(i)) { 195 return false; 196 } 197 } 198 return true; 199} 200 201// Create a modified UTF-8 encoded std::string from a java/lang/String object. 202std::string String::ToModifiedUtf8() { 203 const uint16_t* chars = GetCharArray()->GetData() + GetOffset(); 204 size_t byte_count = GetUtfLength(); 205 std::string result(byte_count, static_cast<char>(0)); 206 ConvertUtf16ToModifiedUtf8(&result[0], chars, GetLength()); 207 return result; 208} 209 210int32_t String::CompareTo(String* rhs) { 211 // Quick test for comparison of a string with itself. 212 String* lhs = this; 213 if (lhs == rhs) { 214 return 0; 215 } 216 // TODO: is this still true? 217 // The annoying part here is that 0x00e9 - 0xffff != 0x00ea, 218 // because the interpreter converts the characters to 32-bit integers 219 // *without* sign extension before it subtracts them (which makes some 220 // sense since "char" is unsigned). So what we get is the result of 221 // 0x000000e9 - 0x0000ffff, which is 0xffff00ea. 222 int32_t lhsCount = lhs->GetLength(); 223 int32_t rhsCount = rhs->GetLength(); 224 int32_t countDiff = lhsCount - rhsCount; 225 int32_t minCount = (countDiff < 0) ? lhsCount : rhsCount; 226 const uint16_t* lhsChars = lhs->GetCharArray()->GetData() + lhs->GetOffset(); 227 const uint16_t* rhsChars = rhs->GetCharArray()->GetData() + rhs->GetOffset(); 228 int32_t otherRes = MemCmp16(lhsChars, rhsChars, minCount); 229 if (otherRes != 0) { 230 return otherRes; 231 } 232 return countDiff; 233} 234 235void String::VisitRoots(RootCallback* callback, void* arg) { 236 if (!java_lang_String_.IsNull()) { 237 java_lang_String_.VisitRoot(callback, arg, 0, kRootStickyClass); 238 } 239} 240 241} // namespace mirror 242} // namespace art 243