xref: /aosp_15_r20/art/runtime/mirror/string.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2011 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker  *
4*795d594fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker  *
8*795d594fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker  *
10*795d594fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker  * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker  */
16*795d594fSAndroid Build Coastguard Worker 
17*795d594fSAndroid Build Coastguard Worker #include "string-alloc-inl.h"
18*795d594fSAndroid Build Coastguard Worker 
19*795d594fSAndroid Build Coastguard Worker #include "arch/memcmp16.h"
20*795d594fSAndroid Build Coastguard Worker #include "array-alloc-inl.h"
21*795d594fSAndroid Build Coastguard Worker #include "base/array_ref.h"
22*795d594fSAndroid Build Coastguard Worker #include "base/casts.h"
23*795d594fSAndroid Build Coastguard Worker #include "base/stl_util.h"
24*795d594fSAndroid Build Coastguard Worker #include "class-inl.h"
25*795d594fSAndroid Build Coastguard Worker #include "dex/descriptors_names.h"
26*795d594fSAndroid Build Coastguard Worker #include "dex/utf-inl.h"
27*795d594fSAndroid Build Coastguard Worker #include "gc/accounting/card_table-inl.h"
28*795d594fSAndroid Build Coastguard Worker #include "handle_scope-inl.h"
29*795d594fSAndroid Build Coastguard Worker #include "intern_table.h"
30*795d594fSAndroid Build Coastguard Worker #include "object-inl.h"
31*795d594fSAndroid Build Coastguard Worker #include "runtime.h"
32*795d594fSAndroid Build Coastguard Worker #include "string-inl.h"
33*795d594fSAndroid Build Coastguard Worker #include "thread.h"
34*795d594fSAndroid Build Coastguard Worker 
35*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
36*795d594fSAndroid Build Coastguard Worker namespace mirror {
37*795d594fSAndroid Build Coastguard Worker 
FastIndexOf(int32_t ch,int32_t start)38*795d594fSAndroid Build Coastguard Worker int32_t String::FastIndexOf(int32_t ch, int32_t start) {
39*795d594fSAndroid Build Coastguard Worker   int32_t count = GetLength();
40*795d594fSAndroid Build Coastguard Worker   if (start >= count) {
41*795d594fSAndroid Build Coastguard Worker     return -1;
42*795d594fSAndroid Build Coastguard Worker   } else if (start < 0) {
43*795d594fSAndroid Build Coastguard Worker     start = 0;
44*795d594fSAndroid Build Coastguard Worker   }
45*795d594fSAndroid Build Coastguard Worker   if (IsCompressed()) {
46*795d594fSAndroid Build Coastguard Worker     return FastIndexOf<uint8_t>(GetValueCompressed(), ch, start);
47*795d594fSAndroid Build Coastguard Worker   } else {
48*795d594fSAndroid Build Coastguard Worker     return FastIndexOf<uint16_t>(GetValue(), ch, start);
49*795d594fSAndroid Build Coastguard Worker   }
50*795d594fSAndroid Build Coastguard Worker }
51*795d594fSAndroid Build Coastguard Worker 
LastIndexOf(int32_t ch)52*795d594fSAndroid Build Coastguard Worker int32_t String::LastIndexOf(int32_t ch) {
53*795d594fSAndroid Build Coastguard Worker   int32_t count = GetLength();
54*795d594fSAndroid Build Coastguard Worker   if (count == 0) {
55*795d594fSAndroid Build Coastguard Worker     return -1;
56*795d594fSAndroid Build Coastguard Worker   }
57*795d594fSAndroid Build Coastguard Worker   if (IsCompressed()) {
58*795d594fSAndroid Build Coastguard Worker     return LastIndexOf<uint8_t>(GetValueCompressed(), ch, count - 1);
59*795d594fSAndroid Build Coastguard Worker   } else {
60*795d594fSAndroid Build Coastguard Worker     return LastIndexOf<uint16_t>(GetValue(), ch, count - 1);
61*795d594fSAndroid Build Coastguard Worker   }
62*795d594fSAndroid Build Coastguard Worker }
63*795d594fSAndroid Build Coastguard Worker 
ComputeAndSetHashCode()64*795d594fSAndroid Build Coastguard Worker int32_t String::ComputeAndSetHashCode() {
65*795d594fSAndroid Build Coastguard Worker   int32_t new_hash_code = ComputeHashCode();
66*795d594fSAndroid Build Coastguard Worker   SetHashCode(new_hash_code);
67*795d594fSAndroid Build Coastguard Worker   return new_hash_code;
68*795d594fSAndroid Build Coastguard Worker }
69*795d594fSAndroid Build Coastguard Worker 
AllASCIIExcept(const uint16_t * chars,int32_t length,uint16_t non_ascii)70*795d594fSAndroid Build Coastguard Worker inline bool String::AllASCIIExcept(const uint16_t* chars, int32_t length, uint16_t non_ascii) {
71*795d594fSAndroid Build Coastguard Worker   DCHECK(!IsASCII(non_ascii));
72*795d594fSAndroid Build Coastguard Worker   for (int32_t i = 0; i < length; ++i) {
73*795d594fSAndroid Build Coastguard Worker     if (!IsASCII(chars[i]) && chars[i] != non_ascii) {
74*795d594fSAndroid Build Coastguard Worker       return false;
75*795d594fSAndroid Build Coastguard Worker     }
76*795d594fSAndroid Build Coastguard Worker   }
77*795d594fSAndroid Build Coastguard Worker   return true;
78*795d594fSAndroid Build Coastguard Worker }
79*795d594fSAndroid Build Coastguard Worker 
DoReplace(Thread * self,Handle<String> src,uint16_t old_c,uint16_t new_c)80*795d594fSAndroid Build Coastguard Worker ObjPtr<String> String::DoReplace(Thread* self, Handle<String> src, uint16_t old_c, uint16_t new_c) {
81*795d594fSAndroid Build Coastguard Worker   int32_t length = src->GetLength();
82*795d594fSAndroid Build Coastguard Worker   DCHECK(src->IsCompressed()
83*795d594fSAndroid Build Coastguard Worker              ? ContainsElement(ArrayRef<uint8_t>(src->value_compressed_, length), old_c)
84*795d594fSAndroid Build Coastguard Worker              : ContainsElement(ArrayRef<uint16_t>(src->value_, length), old_c));
85*795d594fSAndroid Build Coastguard Worker   bool compressible =
86*795d594fSAndroid Build Coastguard Worker       kUseStringCompression &&
87*795d594fSAndroid Build Coastguard Worker       IsASCII(new_c) &&
88*795d594fSAndroid Build Coastguard Worker       (src->IsCompressed() || (!IsASCII(old_c) && AllASCIIExcept(src->value_, length, old_c)));
89*795d594fSAndroid Build Coastguard Worker   gc::AllocatorType allocator_type = Runtime::Current()->GetHeap()->GetCurrentAllocator();
90*795d594fSAndroid Build Coastguard Worker   const int32_t length_with_flag = String::GetFlaggedCount(length, compressible);
91*795d594fSAndroid Build Coastguard Worker 
92*795d594fSAndroid Build Coastguard Worker   auto visitor = [=](ObjPtr<Object> obj, size_t usable_size) REQUIRES_SHARED(Locks::mutator_lock_) {
93*795d594fSAndroid Build Coastguard Worker     SetStringCountVisitor set_string_count_visitor(length_with_flag);
94*795d594fSAndroid Build Coastguard Worker     set_string_count_visitor(obj, usable_size);
95*795d594fSAndroid Build Coastguard Worker     ObjPtr<String> new_string = obj->AsString();
96*795d594fSAndroid Build Coastguard Worker     if (compressible) {
97*795d594fSAndroid Build Coastguard Worker       auto replace = [old_c, new_c](uint16_t c) {
98*795d594fSAndroid Build Coastguard Worker         return dchecked_integral_cast<uint8_t>((old_c != c) ? c : new_c);
99*795d594fSAndroid Build Coastguard Worker       };
100*795d594fSAndroid Build Coastguard Worker       uint8_t* out = new_string->value_compressed_;
101*795d594fSAndroid Build Coastguard Worker       if (LIKELY(src->IsCompressed())) {  // LIKELY(compressible == src->IsCompressed())
102*795d594fSAndroid Build Coastguard Worker         std::transform(src->value_compressed_, src->value_compressed_ + length, out, replace);
103*795d594fSAndroid Build Coastguard Worker       } else {
104*795d594fSAndroid Build Coastguard Worker         std::transform(src->value_, src->value_ + length, out, replace);
105*795d594fSAndroid Build Coastguard Worker       }
106*795d594fSAndroid Build Coastguard Worker       DCHECK(kUseStringCompression && AllASCII(out, length));
107*795d594fSAndroid Build Coastguard Worker     } else {
108*795d594fSAndroid Build Coastguard Worker       auto replace = [old_c, new_c](uint16_t c) {
109*795d594fSAndroid Build Coastguard Worker         return (old_c != c) ? c : new_c;
110*795d594fSAndroid Build Coastguard Worker       };
111*795d594fSAndroid Build Coastguard Worker       uint16_t* out = new_string->value_;
112*795d594fSAndroid Build Coastguard Worker       if (UNLIKELY(src->IsCompressed())) {  // LIKELY(compressible == src->IsCompressed())
113*795d594fSAndroid Build Coastguard Worker         std::transform(src->value_compressed_, src->value_compressed_ + length, out, replace);
114*795d594fSAndroid Build Coastguard Worker       } else {
115*795d594fSAndroid Build Coastguard Worker         std::transform(src->value_, src->value_ + length, out, replace);
116*795d594fSAndroid Build Coastguard Worker       }
117*795d594fSAndroid Build Coastguard Worker       DCHECK_IMPLIES(kUseStringCompression, !AllASCII(out, length));
118*795d594fSAndroid Build Coastguard Worker     }
119*795d594fSAndroid Build Coastguard Worker   };
120*795d594fSAndroid Build Coastguard Worker   return Alloc(self, length_with_flag, allocator_type, visitor);
121*795d594fSAndroid Build Coastguard Worker }
122*795d594fSAndroid Build Coastguard Worker 
DoConcat(Thread * self,Handle<String> h_this,Handle<String> h_arg)123*795d594fSAndroid Build Coastguard Worker ObjPtr<String> String::DoConcat(Thread* self, Handle<String> h_this, Handle<String> h_arg) {
124*795d594fSAndroid Build Coastguard Worker   int32_t length_this = h_this->GetLength();
125*795d594fSAndroid Build Coastguard Worker   int32_t length_arg = h_arg->GetLength();
126*795d594fSAndroid Build Coastguard Worker   gc::AllocatorType allocator_type = Runtime::Current()->GetHeap()->GetCurrentAllocator();
127*795d594fSAndroid Build Coastguard Worker   const bool compressible =
128*795d594fSAndroid Build Coastguard Worker       kUseStringCompression && (h_this->IsCompressed() && h_arg->IsCompressed());
129*795d594fSAndroid Build Coastguard Worker   const int32_t length_with_flag = String::GetFlaggedCount(length_this + length_arg, compressible);
130*795d594fSAndroid Build Coastguard Worker 
131*795d594fSAndroid Build Coastguard Worker   auto visitor = [=](ObjPtr<Object> obj, size_t usable_size) REQUIRES_SHARED(Locks::mutator_lock_) {
132*795d594fSAndroid Build Coastguard Worker     SetStringCountVisitor set_string_count_visitor(length_with_flag);
133*795d594fSAndroid Build Coastguard Worker     set_string_count_visitor(obj, usable_size);
134*795d594fSAndroid Build Coastguard Worker     ObjPtr<String> new_string = obj->AsString();
135*795d594fSAndroid Build Coastguard Worker     if (compressible) {
136*795d594fSAndroid Build Coastguard Worker       uint8_t* new_value = new_string->GetValueCompressed();
137*795d594fSAndroid Build Coastguard Worker       memcpy(new_value, h_this->GetValueCompressed(), length_this * sizeof(uint8_t));
138*795d594fSAndroid Build Coastguard Worker       memcpy(new_value + length_this, h_arg->GetValueCompressed(), length_arg * sizeof(uint8_t));
139*795d594fSAndroid Build Coastguard Worker     } else {
140*795d594fSAndroid Build Coastguard Worker       uint16_t* new_value = new_string->GetValue();
141*795d594fSAndroid Build Coastguard Worker       if (h_this->IsCompressed()) {
142*795d594fSAndroid Build Coastguard Worker         const uint8_t* value_this = h_this->GetValueCompressed();
143*795d594fSAndroid Build Coastguard Worker         for (int i = 0; i < length_this; ++i) {
144*795d594fSAndroid Build Coastguard Worker           new_value[i] = value_this[i];
145*795d594fSAndroid Build Coastguard Worker         }
146*795d594fSAndroid Build Coastguard Worker       } else {
147*795d594fSAndroid Build Coastguard Worker         memcpy(new_value, h_this->GetValue(), length_this * sizeof(uint16_t));
148*795d594fSAndroid Build Coastguard Worker       }
149*795d594fSAndroid Build Coastguard Worker       if (h_arg->IsCompressed()) {
150*795d594fSAndroid Build Coastguard Worker         const uint8_t* value_arg = h_arg->GetValueCompressed();
151*795d594fSAndroid Build Coastguard Worker         for (int i = 0; i < length_arg; ++i) {
152*795d594fSAndroid Build Coastguard Worker           new_value[i + length_this] = value_arg[i];
153*795d594fSAndroid Build Coastguard Worker         }
154*795d594fSAndroid Build Coastguard Worker       } else {
155*795d594fSAndroid Build Coastguard Worker         memcpy(new_value + length_this, h_arg->GetValue(), length_arg * sizeof(uint16_t));
156*795d594fSAndroid Build Coastguard Worker       }
157*795d594fSAndroid Build Coastguard Worker     }
158*795d594fSAndroid Build Coastguard Worker   };
159*795d594fSAndroid Build Coastguard Worker   return Alloc(self, length_with_flag, allocator_type, visitor);
160*795d594fSAndroid Build Coastguard Worker }
161*795d594fSAndroid Build Coastguard Worker 
162*795d594fSAndroid Build Coastguard Worker template<typename T>
RepeatCharacters(ObjPtr<String> new_string,Handle<String> h_this,int32_t count)163*795d594fSAndroid Build Coastguard Worker static void RepeatCharacters(ObjPtr<String> new_string, Handle<String> h_this, int32_t count)
164*795d594fSAndroid Build Coastguard Worker     REQUIRES_SHARED(Locks::mutator_lock_) {
165*795d594fSAndroid Build Coastguard Worker   T *new_value, *h_this_value;
166*795d594fSAndroid Build Coastguard Worker   if constexpr (std::is_same_v<T, uint8_t>) {
167*795d594fSAndroid Build Coastguard Worker     new_value = new_string->GetValueCompressed();
168*795d594fSAndroid Build Coastguard Worker     h_this_value = h_this->GetValueCompressed();
169*795d594fSAndroid Build Coastguard Worker   } else {
170*795d594fSAndroid Build Coastguard Worker     new_value = new_string->GetValue();
171*795d594fSAndroid Build Coastguard Worker     h_this_value = h_this->GetValue();
172*795d594fSAndroid Build Coastguard Worker   }
173*795d594fSAndroid Build Coastguard Worker   int32_t length_this = h_this->GetLength();
174*795d594fSAndroid Build Coastguard Worker   if (length_this == 1) {
175*795d594fSAndroid Build Coastguard Worker     // compiler is smart enough to use memset for uint8_t
176*795d594fSAndroid Build Coastguard Worker     std::fill(new_value, new_value + count, h_this_value[0]);
177*795d594fSAndroid Build Coastguard Worker   } else {
178*795d594fSAndroid Build Coastguard Worker     memcpy(new_value, h_this_value, length_this * sizeof(T));
179*795d594fSAndroid Build Coastguard Worker     int32_t copied = length_this;
180*795d594fSAndroid Build Coastguard Worker     int32_t limit = length_this * count;
181*795d594fSAndroid Build Coastguard Worker     for (; copied < limit - copied; copied <<= 1) {
182*795d594fSAndroid Build Coastguard Worker       memcpy(new_value + copied, new_value, copied * sizeof(T));
183*795d594fSAndroid Build Coastguard Worker     }
184*795d594fSAndroid Build Coastguard Worker     memcpy(new_value + copied, new_value, (limit - copied) * sizeof(T));
185*795d594fSAndroid Build Coastguard Worker   }
186*795d594fSAndroid Build Coastguard Worker }
187*795d594fSAndroid Build Coastguard Worker 
DoRepeat(Thread * self,Handle<String> h_this,int32_t count)188*795d594fSAndroid Build Coastguard Worker ObjPtr<String> String::DoRepeat(Thread* self, Handle<String> h_this, int32_t count) {
189*795d594fSAndroid Build Coastguard Worker   int32_t length_this = h_this->GetLength();
190*795d594fSAndroid Build Coastguard Worker   DCHECK_GT(count, 1);
191*795d594fSAndroid Build Coastguard Worker   DCHECK_LE(length_this, std::numeric_limits<int32_t>::max() / count);
192*795d594fSAndroid Build Coastguard Worker   gc::AllocatorType allocator_type = Runtime::Current()->GetHeap()->GetCurrentAllocator();
193*795d594fSAndroid Build Coastguard Worker   const bool compressible = kUseStringCompression && (h_this->IsCompressed());
194*795d594fSAndroid Build Coastguard Worker   const int32_t length_with_flag = String::GetFlaggedCount(length_this * count, compressible);
195*795d594fSAndroid Build Coastguard Worker 
196*795d594fSAndroid Build Coastguard Worker   auto visitor = [=](ObjPtr<Object> obj, size_t usable_size) REQUIRES_SHARED(Locks::mutator_lock_) {
197*795d594fSAndroid Build Coastguard Worker       SetStringCountVisitor set_string_count_visitor(length_with_flag);
198*795d594fSAndroid Build Coastguard Worker       set_string_count_visitor(obj, usable_size);
199*795d594fSAndroid Build Coastguard Worker       ObjPtr<String> new_string = obj->AsString();
200*795d594fSAndroid Build Coastguard Worker 
201*795d594fSAndroid Build Coastguard Worker       if (compressible) {
202*795d594fSAndroid Build Coastguard Worker         RepeatCharacters<uint8_t>(new_string, h_this, count);
203*795d594fSAndroid Build Coastguard Worker       } else {
204*795d594fSAndroid Build Coastguard Worker         RepeatCharacters<uint16_t>(new_string, h_this, count);
205*795d594fSAndroid Build Coastguard Worker       }
206*795d594fSAndroid Build Coastguard Worker   };
207*795d594fSAndroid Build Coastguard Worker   return Alloc(self, length_with_flag, allocator_type, visitor);
208*795d594fSAndroid Build Coastguard Worker }
209*795d594fSAndroid Build Coastguard Worker 
AllocFromUtf16(Thread * self,int32_t utf16_length,const uint16_t * utf16_data_in)210*795d594fSAndroid Build Coastguard Worker ObjPtr<String> String::AllocFromUtf16(Thread* self,
211*795d594fSAndroid Build Coastguard Worker                                       int32_t utf16_length,
212*795d594fSAndroid Build Coastguard Worker                                       const uint16_t* utf16_data_in) {
213*795d594fSAndroid Build Coastguard Worker   CHECK_IMPLIES(utf16_data_in == nullptr, utf16_length == 0);
214*795d594fSAndroid Build Coastguard Worker   gc::AllocatorType allocator_type = Runtime::Current()->GetHeap()->GetCurrentAllocator();
215*795d594fSAndroid Build Coastguard Worker   const bool compressible = kUseStringCompression &&
216*795d594fSAndroid Build Coastguard Worker                             String::AllASCII<uint16_t>(utf16_data_in, utf16_length);
217*795d594fSAndroid Build Coastguard Worker   int32_t length_with_flag = String::GetFlaggedCount(utf16_length, compressible);
218*795d594fSAndroid Build Coastguard Worker 
219*795d594fSAndroid Build Coastguard Worker   auto visitor = [=](ObjPtr<Object> obj, size_t usable_size) REQUIRES_SHARED(Locks::mutator_lock_) {
220*795d594fSAndroid Build Coastguard Worker     SetStringCountVisitor set_string_count_visitor(length_with_flag);
221*795d594fSAndroid Build Coastguard Worker     set_string_count_visitor(obj, usable_size);
222*795d594fSAndroid Build Coastguard Worker     ObjPtr<String> new_string = obj->AsString();
223*795d594fSAndroid Build Coastguard Worker     if (compressible) {
224*795d594fSAndroid Build Coastguard Worker       uint8_t* value = new_string->GetValueCompressed();
225*795d594fSAndroid Build Coastguard Worker       for (int i = 0; i < utf16_length; ++i) {
226*795d594fSAndroid Build Coastguard Worker         value[i] = static_cast<uint8_t>(utf16_data_in[i]);
227*795d594fSAndroid Build Coastguard Worker       }
228*795d594fSAndroid Build Coastguard Worker     } else {
229*795d594fSAndroid Build Coastguard Worker       memcpy(new_string->GetValue(), utf16_data_in, utf16_length * sizeof(uint16_t));
230*795d594fSAndroid Build Coastguard Worker     }
231*795d594fSAndroid Build Coastguard Worker   };
232*795d594fSAndroid Build Coastguard Worker   return Alloc(self, length_with_flag, allocator_type, visitor);
233*795d594fSAndroid Build Coastguard Worker }
234*795d594fSAndroid Build Coastguard Worker 
AllocFromModifiedUtf8(Thread * self,const char * utf)235*795d594fSAndroid Build Coastguard Worker ObjPtr<String> String::AllocFromModifiedUtf8(Thread* self, const char* utf) {
236*795d594fSAndroid Build Coastguard Worker   DCHECK(utf != nullptr);
237*795d594fSAndroid Build Coastguard Worker   size_t byte_count = strlen(utf);
238*795d594fSAndroid Build Coastguard Worker   size_t char_count = CountModifiedUtf8Chars(utf, byte_count);
239*795d594fSAndroid Build Coastguard Worker   return AllocFromModifiedUtf8(self, char_count, utf, byte_count);
240*795d594fSAndroid Build Coastguard Worker }
241*795d594fSAndroid Build Coastguard Worker 
AllocFromModifiedUtf8(Thread * self,int32_t utf16_length,const char * utf8_data_in)242*795d594fSAndroid Build Coastguard Worker ObjPtr<String> String::AllocFromModifiedUtf8(Thread* self,
243*795d594fSAndroid Build Coastguard Worker                                              int32_t utf16_length,
244*795d594fSAndroid Build Coastguard Worker                                              const char* utf8_data_in) {
245*795d594fSAndroid Build Coastguard Worker   return AllocFromModifiedUtf8(self, utf16_length, utf8_data_in, strlen(utf8_data_in));
246*795d594fSAndroid Build Coastguard Worker }
247*795d594fSAndroid Build Coastguard Worker 
AllocFromModifiedUtf8(Thread * self,int32_t utf16_length,const char * utf8_data_in,int32_t utf8_length)248*795d594fSAndroid Build Coastguard Worker ObjPtr<String> String::AllocFromModifiedUtf8(Thread* self,
249*795d594fSAndroid Build Coastguard Worker                                              int32_t utf16_length,
250*795d594fSAndroid Build Coastguard Worker                                              const char* utf8_data_in,
251*795d594fSAndroid Build Coastguard Worker                                              int32_t utf8_length) {
252*795d594fSAndroid Build Coastguard Worker   gc::AllocatorType allocator_type = Runtime::Current()->GetHeap()->GetCurrentAllocator();
253*795d594fSAndroid Build Coastguard Worker   const bool compressible = kUseStringCompression && (utf16_length == utf8_length);
254*795d594fSAndroid Build Coastguard Worker   const int32_t length_with_flag = String::GetFlaggedCount(utf16_length, compressible);
255*795d594fSAndroid Build Coastguard Worker 
256*795d594fSAndroid Build Coastguard Worker   auto visitor = [=](ObjPtr<Object> obj, size_t usable_size) REQUIRES_SHARED(Locks::mutator_lock_) {
257*795d594fSAndroid Build Coastguard Worker     SetStringCountVisitor set_string_count_visitor(length_with_flag);
258*795d594fSAndroid Build Coastguard Worker     set_string_count_visitor(obj, usable_size);
259*795d594fSAndroid Build Coastguard Worker     ObjPtr<String> new_string = obj->AsString();
260*795d594fSAndroid Build Coastguard Worker     if (compressible) {
261*795d594fSAndroid Build Coastguard Worker       memcpy(new_string->GetValueCompressed(), utf8_data_in, utf16_length * sizeof(uint8_t));
262*795d594fSAndroid Build Coastguard Worker     } else {
263*795d594fSAndroid Build Coastguard Worker       uint16_t* utf16_data_out = new_string->GetValue();
264*795d594fSAndroid Build Coastguard Worker       ConvertModifiedUtf8ToUtf16(utf16_data_out, utf16_length, utf8_data_in, utf8_length);
265*795d594fSAndroid Build Coastguard Worker     }
266*795d594fSAndroid Build Coastguard Worker   };
267*795d594fSAndroid Build Coastguard Worker   return Alloc(self, length_with_flag, allocator_type, visitor);
268*795d594fSAndroid Build Coastguard Worker }
269*795d594fSAndroid Build Coastguard Worker 
Equals(mirror::String * that)270*795d594fSAndroid Build Coastguard Worker bool String::Equals(mirror::String* that) {
271*795d594fSAndroid Build Coastguard Worker   if (this == that) {
272*795d594fSAndroid Build Coastguard Worker     // Quick reference equality test
273*795d594fSAndroid Build Coastguard Worker     return true;
274*795d594fSAndroid Build Coastguard Worker   } else if (that == nullptr) {
275*795d594fSAndroid Build Coastguard Worker     // Null isn't an instanceof anything
276*795d594fSAndroid Build Coastguard Worker     return false;
277*795d594fSAndroid Build Coastguard Worker   } else if (this->GetCount() != that->GetCount()) {
278*795d594fSAndroid Build Coastguard Worker     // Quick length and compression inequality test
279*795d594fSAndroid Build Coastguard Worker     return false;
280*795d594fSAndroid Build Coastguard Worker   } else {
281*795d594fSAndroid Build Coastguard Worker     // Note: don't short circuit on hash code as we're presumably here as the
282*795d594fSAndroid Build Coastguard Worker     // hash code was already equal
283*795d594fSAndroid Build Coastguard Worker     if (this->IsCompressed()) {
284*795d594fSAndroid Build Coastguard Worker       return memcmp(this->GetValueCompressed(), that->GetValueCompressed(), this->GetLength()) == 0;
285*795d594fSAndroid Build Coastguard Worker     } else {
286*795d594fSAndroid Build Coastguard Worker       return memcmp(this->GetValue(), that->GetValue(), sizeof(uint16_t) * this->GetLength()) == 0;
287*795d594fSAndroid Build Coastguard Worker     }
288*795d594fSAndroid Build Coastguard Worker   }
289*795d594fSAndroid Build Coastguard Worker }
290*795d594fSAndroid Build Coastguard Worker 
Equals(const char * modified_utf8)291*795d594fSAndroid Build Coastguard Worker bool String::Equals(const char* modified_utf8) {
292*795d594fSAndroid Build Coastguard Worker   const int32_t length = GetLength();
293*795d594fSAndroid Build Coastguard Worker   if (IsCompressed()) {
294*795d594fSAndroid Build Coastguard Worker     return strlen(modified_utf8) == dchecked_integral_cast<uint32_t>(length) &&
295*795d594fSAndroid Build Coastguard Worker            memcmp(modified_utf8, GetValueCompressed(), length) == 0;
296*795d594fSAndroid Build Coastguard Worker   }
297*795d594fSAndroid Build Coastguard Worker   const uint16_t* value = GetValue();
298*795d594fSAndroid Build Coastguard Worker   int32_t i = 0;
299*795d594fSAndroid Build Coastguard Worker   while (i < length) {
300*795d594fSAndroid Build Coastguard Worker     const uint32_t ch = GetUtf16FromUtf8(&modified_utf8);
301*795d594fSAndroid Build Coastguard Worker     if (ch == '\0') {
302*795d594fSAndroid Build Coastguard Worker       return false;
303*795d594fSAndroid Build Coastguard Worker     }
304*795d594fSAndroid Build Coastguard Worker 
305*795d594fSAndroid Build Coastguard Worker     if (GetLeadingUtf16Char(ch) != value[i++]) {
306*795d594fSAndroid Build Coastguard Worker       return false;
307*795d594fSAndroid Build Coastguard Worker     }
308*795d594fSAndroid Build Coastguard Worker 
309*795d594fSAndroid Build Coastguard Worker     const uint16_t trailing = GetTrailingUtf16Char(ch);
310*795d594fSAndroid Build Coastguard Worker     if (trailing != 0) {
311*795d594fSAndroid Build Coastguard Worker       if (i == length) {
312*795d594fSAndroid Build Coastguard Worker         return false;
313*795d594fSAndroid Build Coastguard Worker       }
314*795d594fSAndroid Build Coastguard Worker 
315*795d594fSAndroid Build Coastguard Worker       if (value[i++] != trailing) {
316*795d594fSAndroid Build Coastguard Worker         return false;
317*795d594fSAndroid Build Coastguard Worker       }
318*795d594fSAndroid Build Coastguard Worker     }
319*795d594fSAndroid Build Coastguard Worker   }
320*795d594fSAndroid Build Coastguard Worker   return *modified_utf8 == '\0';
321*795d594fSAndroid Build Coastguard Worker }
322*795d594fSAndroid Build Coastguard Worker 
323*795d594fSAndroid Build Coastguard Worker // Create a modified UTF-8 encoded std::string from a java/lang/String object.
ToModifiedUtf8()324*795d594fSAndroid Build Coastguard Worker std::string String::ToModifiedUtf8() {
325*795d594fSAndroid Build Coastguard Worker   if (IsCompressed()) {
326*795d594fSAndroid Build Coastguard Worker     return std::string(reinterpret_cast<const char*>(GetValueCompressed()), GetLength());
327*795d594fSAndroid Build Coastguard Worker   } else {
328*795d594fSAndroid Build Coastguard Worker     size_t byte_count = GetModifiedUtf8Length();
329*795d594fSAndroid Build Coastguard Worker     std::string result(byte_count, static_cast<char>(0));
330*795d594fSAndroid Build Coastguard Worker     ConvertUtf16ToModifiedUtf8(&result[0], byte_count, GetValue(), GetLength());
331*795d594fSAndroid Build Coastguard Worker     return result;
332*795d594fSAndroid Build Coastguard Worker   }
333*795d594fSAndroid Build Coastguard Worker }
334*795d594fSAndroid Build Coastguard Worker 
CompareTo(ObjPtr<String> rhs)335*795d594fSAndroid Build Coastguard Worker int32_t String::CompareTo(ObjPtr<String> rhs) {
336*795d594fSAndroid Build Coastguard Worker   // Quick test for comparison of a string with itself.
337*795d594fSAndroid Build Coastguard Worker   ObjPtr<String> lhs = this;
338*795d594fSAndroid Build Coastguard Worker   if (lhs == rhs) {
339*795d594fSAndroid Build Coastguard Worker     return 0;
340*795d594fSAndroid Build Coastguard Worker   }
341*795d594fSAndroid Build Coastguard Worker   int32_t lhs_count = lhs->GetLength();
342*795d594fSAndroid Build Coastguard Worker   int32_t rhs_count = rhs->GetLength();
343*795d594fSAndroid Build Coastguard Worker   int32_t count_diff = lhs_count - rhs_count;
344*795d594fSAndroid Build Coastguard Worker   int32_t min_count = (count_diff < 0) ? lhs_count : rhs_count;
345*795d594fSAndroid Build Coastguard Worker   if (lhs->IsCompressed() && rhs->IsCompressed()) {
346*795d594fSAndroid Build Coastguard Worker     const uint8_t* lhs_chars = lhs->GetValueCompressed();
347*795d594fSAndroid Build Coastguard Worker     const uint8_t* rhs_chars = rhs->GetValueCompressed();
348*795d594fSAndroid Build Coastguard Worker     for (int32_t i = 0; i < min_count; ++i) {
349*795d594fSAndroid Build Coastguard Worker       int32_t char_diff = static_cast<int32_t>(lhs_chars[i]) - static_cast<int32_t>(rhs_chars[i]);
350*795d594fSAndroid Build Coastguard Worker       if (char_diff != 0) {
351*795d594fSAndroid Build Coastguard Worker         return char_diff;
352*795d594fSAndroid Build Coastguard Worker       }
353*795d594fSAndroid Build Coastguard Worker     }
354*795d594fSAndroid Build Coastguard Worker   } else if (lhs->IsCompressed() || rhs->IsCompressed()) {
355*795d594fSAndroid Build Coastguard Worker     const uint8_t* compressed_chars =
356*795d594fSAndroid Build Coastguard Worker         lhs->IsCompressed() ? lhs->GetValueCompressed() : rhs->GetValueCompressed();
357*795d594fSAndroid Build Coastguard Worker     const uint16_t* uncompressed_chars = lhs->IsCompressed() ? rhs->GetValue() : lhs->GetValue();
358*795d594fSAndroid Build Coastguard Worker     for (int32_t i = 0; i < min_count; ++i) {
359*795d594fSAndroid Build Coastguard Worker       int32_t char_diff =
360*795d594fSAndroid Build Coastguard Worker           static_cast<int32_t>(compressed_chars[i]) - static_cast<int32_t>(uncompressed_chars[i]);
361*795d594fSAndroid Build Coastguard Worker       if (char_diff != 0) {
362*795d594fSAndroid Build Coastguard Worker         return lhs->IsCompressed() ? char_diff : -char_diff;
363*795d594fSAndroid Build Coastguard Worker       }
364*795d594fSAndroid Build Coastguard Worker     }
365*795d594fSAndroid Build Coastguard Worker   } else {
366*795d594fSAndroid Build Coastguard Worker     const uint16_t* lhs_chars = lhs->GetValue();
367*795d594fSAndroid Build Coastguard Worker     const uint16_t* rhs_chars = rhs->GetValue();
368*795d594fSAndroid Build Coastguard Worker     // FIXME: The MemCmp16() name is misleading. It returns the char difference on mismatch
369*795d594fSAndroid Build Coastguard Worker     // where memcmp() only guarantees that the returned value has the same sign.
370*795d594fSAndroid Build Coastguard Worker     int32_t char_diff = MemCmp16(lhs_chars, rhs_chars, min_count);
371*795d594fSAndroid Build Coastguard Worker     if (char_diff != 0) {
372*795d594fSAndroid Build Coastguard Worker       return char_diff;
373*795d594fSAndroid Build Coastguard Worker     }
374*795d594fSAndroid Build Coastguard Worker   }
375*795d594fSAndroid Build Coastguard Worker   return count_diff;
376*795d594fSAndroid Build Coastguard Worker }
377*795d594fSAndroid Build Coastguard Worker 
ToCharArray(Handle<String> h_this,Thread * self)378*795d594fSAndroid Build Coastguard Worker ObjPtr<CharArray> String::ToCharArray(Handle<String> h_this, Thread* self) {
379*795d594fSAndroid Build Coastguard Worker   ObjPtr<CharArray> result = CharArray::Alloc(self, h_this->GetLength());
380*795d594fSAndroid Build Coastguard Worker   if (result != nullptr) {
381*795d594fSAndroid Build Coastguard Worker     if (h_this->IsCompressed()) {
382*795d594fSAndroid Build Coastguard Worker       int32_t length = h_this->GetLength();
383*795d594fSAndroid Build Coastguard Worker       const uint8_t* src = h_this->GetValueCompressed();
384*795d594fSAndroid Build Coastguard Worker       uint16_t* dest = result->GetData();
385*795d594fSAndroid Build Coastguard Worker       for (int i = 0; i < length; ++i) {
386*795d594fSAndroid Build Coastguard Worker         dest[i] = src[i];
387*795d594fSAndroid Build Coastguard Worker       }
388*795d594fSAndroid Build Coastguard Worker     } else {
389*795d594fSAndroid Build Coastguard Worker       memcpy(result->GetData(), h_this->GetValue(), h_this->GetLength() * sizeof(uint16_t));
390*795d594fSAndroid Build Coastguard Worker     }
391*795d594fSAndroid Build Coastguard Worker   } else {
392*795d594fSAndroid Build Coastguard Worker     self->AssertPendingOOMException();
393*795d594fSAndroid Build Coastguard Worker   }
394*795d594fSAndroid Build Coastguard Worker   return result;
395*795d594fSAndroid Build Coastguard Worker }
396*795d594fSAndroid Build Coastguard Worker 
GetChars(int32_t start,int32_t end,Handle<CharArray> array,int32_t index)397*795d594fSAndroid Build Coastguard Worker void String::GetChars(int32_t start, int32_t end, Handle<CharArray> array, int32_t index) {
398*795d594fSAndroid Build Coastguard Worker   uint16_t* data = array->GetData() + index;
399*795d594fSAndroid Build Coastguard Worker   DCHECK_LE(start, end);
400*795d594fSAndroid Build Coastguard Worker   int32_t length = end - start;
401*795d594fSAndroid Build Coastguard Worker   if (IsCompressed()) {
402*795d594fSAndroid Build Coastguard Worker     const uint8_t* value = GetValueCompressed() + start;
403*795d594fSAndroid Build Coastguard Worker     for (int i = 0; i < length; ++i) {
404*795d594fSAndroid Build Coastguard Worker       data[i] = value[i];
405*795d594fSAndroid Build Coastguard Worker     }
406*795d594fSAndroid Build Coastguard Worker   } else {
407*795d594fSAndroid Build Coastguard Worker     uint16_t* value = GetValue() + start;
408*795d594fSAndroid Build Coastguard Worker     memcpy(data, value, length * sizeof(uint16_t));
409*795d594fSAndroid Build Coastguard Worker   }
410*795d594fSAndroid Build Coastguard Worker }
411*795d594fSAndroid Build Coastguard Worker 
FillBytesLatin1(Handle<ByteArray> array,int32_t index)412*795d594fSAndroid Build Coastguard Worker void String::FillBytesLatin1(Handle<ByteArray> array, int32_t index) {
413*795d594fSAndroid Build Coastguard Worker   int8_t* data = array->GetData() + index;
414*795d594fSAndroid Build Coastguard Worker   int32_t length = GetLength();
415*795d594fSAndroid Build Coastguard Worker   if (IsCompressed()) {
416*795d594fSAndroid Build Coastguard Worker     const uint8_t* value = GetValueCompressed();
417*795d594fSAndroid Build Coastguard Worker     memcpy(data, value, length * sizeof(uint8_t));
418*795d594fSAndroid Build Coastguard Worker   } else {
419*795d594fSAndroid Build Coastguard Worker     // Drop the high byte of the characters.
420*795d594fSAndroid Build Coastguard Worker     // The caller should check that all dropped high bytes are zeros.
421*795d594fSAndroid Build Coastguard Worker     const uint16_t* value = GetValue();
422*795d594fSAndroid Build Coastguard Worker     for (int32_t i = 0; i < length; ++i) {
423*795d594fSAndroid Build Coastguard Worker       data[i] = static_cast<int8_t>(dchecked_integral_cast<uint8_t>(value[i]));
424*795d594fSAndroid Build Coastguard Worker     }
425*795d594fSAndroid Build Coastguard Worker   }
426*795d594fSAndroid Build Coastguard Worker }
427*795d594fSAndroid Build Coastguard Worker 
FillBytesUTF16(Handle<ByteArray> array,int32_t index)428*795d594fSAndroid Build Coastguard Worker void String::FillBytesUTF16(Handle<ByteArray> array, int32_t index) {
429*795d594fSAndroid Build Coastguard Worker   int8_t* data = array->GetData() + index;
430*795d594fSAndroid Build Coastguard Worker   int32_t length = GetLength();
431*795d594fSAndroid Build Coastguard Worker   if (IsCompressed()) {
432*795d594fSAndroid Build Coastguard Worker     const uint8_t* value = GetValueCompressed();
433*795d594fSAndroid Build Coastguard Worker     uint32_t d_index = 0;
434*795d594fSAndroid Build Coastguard Worker     for (int i = 0; i < length; ++i) {
435*795d594fSAndroid Build Coastguard Worker       data[d_index++] = static_cast<int8_t>(value[i]);
436*795d594fSAndroid Build Coastguard Worker       data[d_index++] = 0;
437*795d594fSAndroid Build Coastguard Worker     }
438*795d594fSAndroid Build Coastguard Worker   } else {
439*795d594fSAndroid Build Coastguard Worker     const uint16_t* value = GetValue();
440*795d594fSAndroid Build Coastguard Worker     memcpy(data, value, length * sizeof(uint16_t));
441*795d594fSAndroid Build Coastguard Worker   }
442*795d594fSAndroid Build Coastguard Worker }
443*795d594fSAndroid Build Coastguard Worker 
IsValueNull()444*795d594fSAndroid Build Coastguard Worker bool String::IsValueNull() {
445*795d594fSAndroid Build Coastguard Worker   return (IsCompressed()) ? (GetValueCompressed() == nullptr) : (GetValue() == nullptr);
446*795d594fSAndroid Build Coastguard Worker }
447*795d594fSAndroid Build Coastguard Worker 
PrettyStringDescriptor(ObjPtr<mirror::String> java_descriptor)448*795d594fSAndroid Build Coastguard Worker std::string String::PrettyStringDescriptor(ObjPtr<mirror::String> java_descriptor) {
449*795d594fSAndroid Build Coastguard Worker   if (java_descriptor == nullptr) {
450*795d594fSAndroid Build Coastguard Worker     return "null";
451*795d594fSAndroid Build Coastguard Worker   }
452*795d594fSAndroid Build Coastguard Worker   return java_descriptor->PrettyStringDescriptor();
453*795d594fSAndroid Build Coastguard Worker }
454*795d594fSAndroid Build Coastguard Worker 
PrettyStringDescriptor()455*795d594fSAndroid Build Coastguard Worker std::string String::PrettyStringDescriptor() {
456*795d594fSAndroid Build Coastguard Worker   return PrettyDescriptor(ToModifiedUtf8().c_str());
457*795d594fSAndroid Build Coastguard Worker }
458*795d594fSAndroid Build Coastguard Worker 
Intern()459*795d594fSAndroid Build Coastguard Worker ObjPtr<String> String::Intern() {
460*795d594fSAndroid Build Coastguard Worker   return Runtime::Current()->GetInternTable()->InternWeak(this);
461*795d594fSAndroid Build Coastguard Worker }
462*795d594fSAndroid Build Coastguard Worker 
463*795d594fSAndroid Build Coastguard Worker }  // namespace mirror
464*795d594fSAndroid Build Coastguard Worker }  // namespace art
465