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 30 namespace art { 31 namespace mirror { 32 33 // TODO: get global references for these 34 GcRoot<Class> String::java_lang_String_; 35 36 int32_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 54 void 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 60 void String::ResetClass() { 61 CHECK(!java_lang_String_.IsNull()); 62 java_lang_String_ = GcRoot<Class>(nullptr); 63 } 64 65 int32_t String::ComputeHashCode() { 66 const int32_t hash_code = ComputeUtf16Hash(GetCharArray(), GetOffset(), GetLength()); 67 SetHashCode(hash_code); 68 return hash_code; 69 } 70 71 int32_t String::GetUtfLength() { 72 return CountUtf8Bytes(GetCharArray()->GetData() + GetOffset(), GetLength()); 73 } 74 75 String* String::AllocFromUtf16(Thread* self, 76 int32_t utf16_length, 77 const uint16_t* utf16_data_in, 78 int32_t hash_code) { 79 CHECK(utf16_data_in != nullptr || utf16_length == 0); 80 String* string = Alloc(self, utf16_length); 81 if (UNLIKELY(string == nullptr)) { 82 return nullptr; 83 } 84 CharArray* array = const_cast<CharArray*>(string->GetCharArray()); 85 if (UNLIKELY(array == nullptr)) { 86 return nullptr; 87 } 88 memcpy(array->GetData(), utf16_data_in, utf16_length * sizeof(uint16_t)); 89 if (hash_code != 0) { 90 DCHECK_EQ(hash_code, ComputeUtf16Hash(utf16_data_in, utf16_length)); 91 string->SetHashCode(hash_code); 92 } else { 93 string->ComputeHashCode(); 94 } 95 return string; 96 } 97 98 String* String::AllocFromModifiedUtf8(Thread* self, const char* utf) { 99 DCHECK(utf != nullptr); 100 size_t char_count = CountModifiedUtf8Chars(utf); 101 return AllocFromModifiedUtf8(self, char_count, utf); 102 } 103 104 String* String::AllocFromModifiedUtf8(Thread* self, int32_t utf16_length, 105 const char* utf8_data_in) { 106 String* string = Alloc(self, utf16_length); 107 if (UNLIKELY(string == nullptr)) { 108 return nullptr; 109 } 110 uint16_t* utf16_data_out = 111 const_cast<uint16_t*>(string->GetCharArray()->GetData()); 112 ConvertModifiedUtf8ToUtf16(utf16_data_out, utf8_data_in); 113 string->ComputeHashCode(); 114 return string; 115 } 116 117 String* String::Alloc(Thread* self, int32_t utf16_length) { 118 StackHandleScope<1> hs(self); 119 Handle<CharArray> array(hs.NewHandle(CharArray::Alloc(self, utf16_length))); 120 if (UNLIKELY(array.Get() == nullptr)) { 121 return nullptr; 122 } 123 return Alloc(self, array); 124 } 125 126 String* String::Alloc(Thread* self, Handle<CharArray> array) { 127 // Hold reference in case AllocObject causes GC. 128 String* string = down_cast<String*>(GetJavaLangString()->AllocObject(self)); 129 if (LIKELY(string != nullptr)) { 130 string->SetArray(array.Get()); 131 string->SetCount(array->GetLength()); 132 } 133 return string; 134 } 135 136 bool String::Equals(String* that) { 137 if (this == that) { 138 // Quick reference equality test 139 return true; 140 } else if (that == NULL) { 141 // Null isn't an instanceof anything 142 return false; 143 } else if (this->GetLength() != that->GetLength()) { 144 // Quick length inequality test 145 return false; 146 } else { 147 // Note: don't short circuit on hash code as we're presumably here as the 148 // hash code was already equal 149 for (int32_t i = 0; i < that->GetLength(); ++i) { 150 if (this->CharAt(i) != that->CharAt(i)) { 151 return false; 152 } 153 } 154 return true; 155 } 156 } 157 158 bool String::Equals(const uint16_t* that_chars, int32_t that_offset, int32_t that_length) { 159 if (this->GetLength() != that_length) { 160 return false; 161 } else { 162 for (int32_t i = 0; i < that_length; ++i) { 163 if (this->CharAt(i) != that_chars[that_offset + i]) { 164 return false; 165 } 166 } 167 return true; 168 } 169 } 170 171 bool String::Equals(const char* modified_utf8) { 172 for (int32_t i = 0; i < GetLength(); ++i) { 173 uint16_t ch = GetUtf16FromUtf8(&modified_utf8); 174 if (ch == '\0' || ch != CharAt(i)) { 175 return false; 176 } 177 } 178 return *modified_utf8 == '\0'; 179 } 180 181 bool String::Equals(const StringPiece& modified_utf8) { 182 const char* p = modified_utf8.data(); 183 for (int32_t i = 0; i < GetLength(); ++i) { 184 uint16_t ch = GetUtf16FromUtf8(&p); 185 if (ch != CharAt(i)) { 186 return false; 187 } 188 } 189 return true; 190 } 191 192 // Create a modified UTF-8 encoded std::string from a java/lang/String object. 193 std::string String::ToModifiedUtf8() { 194 const uint16_t* chars = GetCharArray()->GetData() + GetOffset(); 195 size_t byte_count = GetUtfLength(); 196 std::string result(byte_count, static_cast<char>(0)); 197 ConvertUtf16ToModifiedUtf8(&result[0], chars, GetLength()); 198 return result; 199 } 200 201 int32_t String::CompareTo(String* rhs) { 202 // Quick test for comparison of a string with itself. 203 String* lhs = this; 204 if (lhs == rhs) { 205 return 0; 206 } 207 // TODO: is this still true? 208 // The annoying part here is that 0x00e9 - 0xffff != 0x00ea, 209 // because the interpreter converts the characters to 32-bit integers 210 // *without* sign extension before it subtracts them (which makes some 211 // sense since "char" is unsigned). So what we get is the result of 212 // 0x000000e9 - 0x0000ffff, which is 0xffff00ea. 213 int32_t lhsCount = lhs->GetLength(); 214 int32_t rhsCount = rhs->GetLength(); 215 int32_t countDiff = lhsCount - rhsCount; 216 int32_t minCount = (countDiff < 0) ? lhsCount : rhsCount; 217 const uint16_t* lhsChars = lhs->GetCharArray()->GetData() + lhs->GetOffset(); 218 const uint16_t* rhsChars = rhs->GetCharArray()->GetData() + rhs->GetOffset(); 219 int32_t otherRes = MemCmp16(lhsChars, rhsChars, minCount); 220 if (otherRes != 0) { 221 return otherRes; 222 } 223 return countDiff; 224 } 225 226 void String::VisitRoots(RootCallback* callback, void* arg) { 227 java_lang_String_.VisitRootIfNonNull(callback, arg, RootInfo(kRootStickyClass)); 228 } 229 230 } // namespace mirror 231 } // namespace art 232