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 #ifndef ART_RUNTIME_MIRROR_STRING_H_ 18 #define ART_RUNTIME_MIRROR_STRING_H_ 19 20 #include "base/bit_utils.h" 21 #include "base/macros.h" 22 #include "class.h" 23 #include "object.h" 24 #include "runtime_globals.h" 25 26 namespace art HIDDEN { 27 28 namespace gc { 29 enum AllocatorType : char; 30 } // namespace gc 31 32 template<class T> class Handle; 33 class InternTable; 34 template<class MirrorType> class ObjPtr; 35 class StringBuilderAppend; 36 struct StringOffsets; 37 class StubTest_ReadBarrierForRoot_Test; 38 39 namespace mirror { 40 41 // String Compression 42 static constexpr bool kUseStringCompression = true; 43 enum class StringCompressionFlag : uint32_t { 44 kCompressed = 0u, 45 kUncompressed = 1u 46 }; 47 48 // C++ mirror of java.lang.String 49 class MANAGED String final : public Object { 50 public: 51 MIRROR_CLASS("Ljava/lang/String;"); 52 53 // Size of java.lang.String.class. 54 static uint32_t ClassSize(PointerSize pointer_size); 55 56 // Size of an instance of java.lang.String not including its value array. InstanceSize()57 static constexpr uint32_t InstanceSize() { 58 return sizeof(String); 59 } 60 CountOffset()61 static constexpr MemberOffset CountOffset() { 62 return OFFSET_OF_OBJECT_MEMBER(String, count_); 63 } 64 ValueOffset()65 static constexpr MemberOffset ValueOffset() { 66 return OFFSET_OF_OBJECT_MEMBER(String, value_); 67 } 68 GetValue()69 uint16_t* GetValue() REQUIRES_SHARED(Locks::mutator_lock_) { 70 return &value_[0]; 71 } 72 GetValueCompressed()73 uint8_t* GetValueCompressed() REQUIRES_SHARED(Locks::mutator_lock_) { 74 return &value_compressed_[0]; 75 } 76 77 template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> SizeOf()78 size_t SizeOf() REQUIRES_SHARED(Locks::mutator_lock_) { 79 size_t size = sizeof(String); 80 if (IsCompressed()) { 81 size += (sizeof(uint8_t) * GetLength<kVerifyFlags>()); 82 } else { 83 size += (sizeof(uint16_t) * GetLength<kVerifyFlags>()); 84 } 85 // String.equals() intrinsics assume zero-padding up to kObjectAlignment, 86 // so make sure the zero-padding is actually copied around if GC compaction 87 // chooses to copy only SizeOf() bytes. 88 // http://b/23528461 89 return RoundUp(size, kObjectAlignment); 90 } 91 92 // Taking out the first/uppermost bit because it is not part of actual length value 93 template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> GetLength()94 int32_t GetLength() REQUIRES_SHARED(Locks::mutator_lock_) { 95 return GetLengthFromCount(GetCount<kVerifyFlags>()); 96 } 97 98 template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> GetCount()99 int32_t GetCount() REQUIRES_SHARED(Locks::mutator_lock_) { 100 return GetField32<kVerifyFlags>(OFFSET_OF_OBJECT_MEMBER(String, count_)); 101 } 102 SetCount(int32_t new_count)103 void SetCount(int32_t new_count) REQUIRES_SHARED(Locks::mutator_lock_) { 104 // Count is invariant so use non-transactional mode. Also disable check as we may run inside 105 // a transaction. 106 SetField32<false, false>(OFFSET_OF_OBJECT_MEMBER(String, count_), new_count); 107 } 108 GetStoredHashCode()109 int32_t GetStoredHashCode() REQUIRES_SHARED(Locks::mutator_lock_) { 110 return GetField32(OFFSET_OF_OBJECT_MEMBER(String, hash_code_)); 111 } 112 113 int32_t GetHashCode() REQUIRES_SHARED(Locks::mutator_lock_); 114 115 // Computes and returns the hash code. 116 int32_t ComputeHashCode() REQUIRES_SHARED(Locks::mutator_lock_); 117 118 int32_t GetModifiedUtf8Length() REQUIRES_SHARED(Locks::mutator_lock_); 119 120 uint16_t CharAt(int32_t index) REQUIRES_SHARED(Locks::mutator_lock_); 121 122 // Create a new string where all occurences of `old_c` are replaced with `new_c`. 123 // String.doReplace(char, char) is called from String.replace(char, char) when there is a match. 124 static ObjPtr<String> DoReplace(Thread* self, Handle<String> src, uint16_t old_c, uint16_t new_c) 125 REQUIRES_SHARED(Locks::mutator_lock_); 126 127 EXPORT ObjPtr<String> Intern() REQUIRES_SHARED(Locks::mutator_lock_); 128 129 template <bool kIsInstrumented = true, typename PreFenceVisitor> 130 ALWAYS_INLINE static ObjPtr<String> Alloc(Thread* self, 131 int32_t utf16_length_with_flag, 132 gc::AllocatorType allocator_type, 133 const PreFenceVisitor& pre_fence_visitor) 134 REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); 135 136 template <bool kIsInstrumented = true> 137 ALWAYS_INLINE static ObjPtr<String> AllocFromByteArray(Thread* self, 138 int32_t byte_length, 139 Handle<ByteArray> array, 140 int32_t offset, 141 int32_t high_byte, 142 gc::AllocatorType allocator_type) 143 REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); 144 145 template <bool kIsInstrumented = true> 146 ALWAYS_INLINE static ObjPtr<String> AllocFromUtf16ByteArray(Thread* self, 147 int32_t char_count, 148 Handle<ByteArray> array, 149 int32_t offset, 150 gc::AllocatorType allocator_type) 151 REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); 152 153 template <bool kIsInstrumented = true> 154 ALWAYS_INLINE static ObjPtr<String> AllocFromCharArray(Thread* self, 155 int32_t count, 156 Handle<CharArray> array, 157 int32_t offset, 158 gc::AllocatorType allocator_type) 159 REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); 160 161 template <bool kIsInstrumented = true> 162 ALWAYS_INLINE static ObjPtr<String> AllocFromString(Thread* self, 163 int32_t string_length, 164 Handle<String> string, 165 int32_t offset, 166 gc::AllocatorType allocator_type) 167 REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); 168 169 template <bool kIsInstrumented = true> 170 ALWAYS_INLINE static ObjPtr<String> AllocEmptyString(Thread* self, 171 gc::AllocatorType allocator_type) 172 REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); 173 174 static ObjPtr<String> DoConcat(Thread* self, Handle<String> h_this, Handle<String> h_arg) 175 REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); 176 177 static ObjPtr<String> DoRepeat(Thread* self, Handle<String> h_this, int32_t count) 178 REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); 179 180 static ObjPtr<String> AllocFromUtf16(Thread* self, 181 int32_t utf16_length, 182 const uint16_t* utf16_data_in) 183 REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); 184 185 EXPORT static ObjPtr<String> AllocFromModifiedUtf8(Thread* self, const char* utf) 186 REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); 187 188 static ObjPtr<String> AllocFromModifiedUtf8(Thread* self, 189 int32_t utf16_length, 190 const char* utf8_data_in, 191 int32_t utf8_length) 192 REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); 193 194 static ObjPtr<String> AllocFromModifiedUtf8(Thread* self, 195 int32_t utf16_length, 196 const char* utf8_data_in) 197 REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); 198 199 bool Equals(const char* modified_utf8) REQUIRES_SHARED(Locks::mutator_lock_); 200 Equals(ObjPtr<mirror::String> that)201 bool Equals(ObjPtr<mirror::String> that) REQUIRES_SHARED(Locks::mutator_lock_) { 202 return Equals(that.Ptr()); 203 } 204 205 // A version that takes a mirror::String pointer instead of ObjPtr as it's being 206 // called by the runtime app image code which can encode mirror::String at 64bit 207 // addresses (ObjPtr only works with 32bit pointers). 208 EXPORT bool Equals(mirror::String* that) REQUIRES_SHARED(Locks::mutator_lock_); 209 210 // Create a modified UTF-8 encoded std::string from a java/lang/String object. 211 EXPORT std::string ToModifiedUtf8() REQUIRES_SHARED(Locks::mutator_lock_); 212 213 int32_t FastIndexOf(int32_t ch, int32_t start) REQUIRES_SHARED(Locks::mutator_lock_); 214 215 template <typename MemoryType> 216 int32_t FastIndexOf(MemoryType* chars, int32_t ch, int32_t start) 217 REQUIRES_SHARED(Locks::mutator_lock_); 218 219 int32_t LastIndexOf(int32_t ch) REQUIRES_SHARED(Locks::mutator_lock_); 220 221 template <typename MemoryType> 222 int32_t LastIndexOf(MemoryType* chars, int32_t ch, int32_t from_index) 223 REQUIRES_SHARED(Locks::mutator_lock_); 224 225 int32_t CompareTo(ObjPtr<String> other) REQUIRES_SHARED(Locks::mutator_lock_); 226 227 static ObjPtr<CharArray> ToCharArray(Handle<String> h_this, Thread* self) 228 REQUIRES_SHARED(Locks::mutator_lock_) 229 REQUIRES(!Roles::uninterruptible_); 230 231 void GetChars(int32_t start, int32_t end, Handle<CharArray> array, int32_t index) 232 REQUIRES_SHARED(Locks::mutator_lock_); 233 234 void FillBytesLatin1(Handle<ByteArray> array, int32_t index) 235 REQUIRES_SHARED(Locks::mutator_lock_); 236 237 void FillBytesUTF16(Handle<ByteArray> array, int32_t index) 238 REQUIRES_SHARED(Locks::mutator_lock_); 239 240 template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> IsCompressed()241 bool IsCompressed() REQUIRES_SHARED(Locks::mutator_lock_) { 242 return kUseStringCompression && IsCompressed(GetCount()); 243 } 244 245 bool IsValueNull() REQUIRES_SHARED(Locks::mutator_lock_); 246 247 template<typename MemoryType> 248 static bool AllASCII(const MemoryType* chars, const int length); 249 250 static bool DexFileStringAllASCII(const char* chars, const int length); 251 IsCompressed(int32_t count)252 ALWAYS_INLINE static bool IsCompressed(int32_t count) { 253 return GetCompressionFlagFromCount(count) == StringCompressionFlag::kCompressed; 254 } 255 GetCompressionFlagFromCount(int32_t count)256 ALWAYS_INLINE static StringCompressionFlag GetCompressionFlagFromCount(int32_t count) { 257 return kUseStringCompression 258 ? static_cast<StringCompressionFlag>(static_cast<uint32_t>(count) & 1u) 259 : StringCompressionFlag::kUncompressed; 260 } 261 GetLengthFromCount(int32_t count)262 ALWAYS_INLINE static int32_t GetLengthFromCount(int32_t count) { 263 return kUseStringCompression ? static_cast<int32_t>(static_cast<uint32_t>(count) >> 1) : count; 264 } 265 GetFlaggedCount(int32_t length,bool compressible)266 ALWAYS_INLINE static int32_t GetFlaggedCount(int32_t length, bool compressible) { 267 return kUseStringCompression 268 ? static_cast<int32_t>((static_cast<uint32_t>(length) << 1) | 269 (static_cast<uint32_t>(compressible 270 ? StringCompressionFlag::kCompressed 271 : StringCompressionFlag::kUncompressed))) 272 : length; 273 } 274 275 // Returns a human-readable equivalent of 'descriptor'. So "I" would be "int", 276 // "[[I" would be "int[][]", "[Ljava/lang/String;" would be 277 // "java.lang.String[]", and so forth. 278 static std::string PrettyStringDescriptor(ObjPtr<mirror::String> descriptor) 279 REQUIRES_SHARED(Locks::mutator_lock_); 280 std::string PrettyStringDescriptor() 281 REQUIRES_SHARED(Locks::mutator_lock_); 282 IsASCII(uint16_t c)283 static constexpr bool IsASCII(uint16_t c) { 284 // Valid ASCII characters are in range 1..0x7f. Zero is not considered ASCII 285 // because it would complicate the detection of ASCII strings in Modified-UTF8. 286 return (c - 1u) < 0x7fu; 287 } 288 289 private: 290 static bool AllASCIIExcept(const uint16_t* chars, int32_t length, uint16_t non_ascii); 291 292 // Computes, stores, and returns the hash code. 293 EXPORT int32_t ComputeAndSetHashCode() REQUIRES_SHARED(Locks::mutator_lock_); 294 SetHashCode(int32_t new_hash_code)295 void SetHashCode(int32_t new_hash_code) REQUIRES_SHARED(Locks::mutator_lock_) { 296 if (kIsDebugBuild) { 297 CHECK_EQ(new_hash_code, ComputeHashCode()); 298 int32_t old_hash_code = GetStoredHashCode(); 299 // Another thread could have raced this one and set the hash code. 300 CHECK(old_hash_code == 0 || old_hash_code == new_hash_code) 301 << "old: " << old_hash_code << " new: " << new_hash_code; 302 } 303 // Hash code is invariant so use non-transactional mode, allowing a failed transaction 304 // to set the hash code anyway. Also disable check as we may run inside a transaction. 305 SetField32</*kTransactionActive=*/ false, /*kCheckTransaction=*/ false>( 306 OFFSET_OF_OBJECT_MEMBER(String, hash_code_), new_hash_code); 307 } 308 309 // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses". 310 311 // If string compression is enabled, count_ holds the StringCompressionFlag in the 312 // least significant bit and the length in the remaining bits, length = count_ >> 1. 313 int32_t count_; 314 315 uint32_t hash_code_; 316 317 // Compression of all-ASCII into 8-bit memory leads to usage one of these fields 318 union { 319 uint16_t value_[0]; 320 uint8_t value_compressed_[0]; 321 }; 322 323 friend class art::InternTable; // Let `InternTable` call `SetHashCode()`. 324 friend class art::StringBuilderAppend; 325 friend struct art::StringOffsets; // for verifying offset information 326 327 DISALLOW_IMPLICIT_CONSTRUCTORS(String); 328 }; 329 330 } // namespace mirror 331 } // namespace art 332 333 #endif // ART_RUNTIME_MIRROR_STRING_H_ 334