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