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 "gc/allocator_type.h" 21 #include "gc_root.h" 22 #include "object.h" 23 24 namespace art { 25 26 template<class T> class Handle; 27 struct StringOffsets; 28 class StringPiece; 29 class StubTest_ReadBarrierForRoot_Test; 30 31 namespace mirror { 32 33 // String Compression 34 static constexpr bool kUseStringCompression = true; 35 enum class StringCompressionFlag : uint32_t { 36 kCompressed = 0u, 37 kUncompressed = 1u 38 }; 39 40 // C++ mirror of java.lang.String 41 class MANAGED String FINAL : public Object { 42 public: 43 // Size of java.lang.String.class. 44 static uint32_t ClassSize(PointerSize pointer_size); 45 46 // Size of an instance of java.lang.String not including its value array. InstanceSize()47 static constexpr uint32_t InstanceSize() { 48 return sizeof(String); 49 } 50 CountOffset()51 static MemberOffset CountOffset() { 52 return OFFSET_OF_OBJECT_MEMBER(String, count_); 53 } 54 ValueOffset()55 static MemberOffset ValueOffset() { 56 return OFFSET_OF_OBJECT_MEMBER(String, value_); 57 } 58 GetValue()59 uint16_t* GetValue() REQUIRES_SHARED(Locks::mutator_lock_) { 60 return &value_[0]; 61 } 62 GetValueCompressed()63 uint8_t* GetValueCompressed() REQUIRES_SHARED(Locks::mutator_lock_) { 64 return &value_compressed_[0]; 65 } 66 67 template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> 68 size_t SizeOf() REQUIRES_SHARED(Locks::mutator_lock_); 69 70 // Taking out the first/uppermost bit because it is not part of actual length value 71 template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> GetLength()72 int32_t GetLength() REQUIRES_SHARED(Locks::mutator_lock_) { 73 return GetLengthFromCount(GetCount<kVerifyFlags>()); 74 } 75 76 template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> GetCount()77 int32_t GetCount() REQUIRES_SHARED(Locks::mutator_lock_) { 78 return GetField32<kVerifyFlags>(OFFSET_OF_OBJECT_MEMBER(String, count_)); 79 } 80 SetCount(int32_t new_count)81 void SetCount(int32_t new_count) REQUIRES_SHARED(Locks::mutator_lock_) { 82 // Count is invariant so use non-transactional mode. Also disable check as we may run inside 83 // a transaction. 84 SetField32<false, false>(OFFSET_OF_OBJECT_MEMBER(String, count_), new_count); 85 } 86 87 int32_t GetHashCode() REQUIRES_SHARED(Locks::mutator_lock_); 88 89 // Computes, stores, and returns the hash code. 90 int32_t ComputeHashCode() REQUIRES_SHARED(Locks::mutator_lock_); 91 92 int32_t GetUtfLength() REQUIRES_SHARED(Locks::mutator_lock_); 93 94 uint16_t CharAt(int32_t index) REQUIRES_SHARED(Locks::mutator_lock_); 95 96 // Create a new string where all occurences of `old_c` are replaced with `new_c`. 97 // String.doReplace(char, char) is called from String.replace(char, char) when there is a match. 98 static ObjPtr<String> DoReplace(Thread* self, Handle<String> src, uint16_t old_c, uint16_t new_c) 99 REQUIRES_SHARED(Locks::mutator_lock_); 100 101 ObjPtr<String> Intern() REQUIRES_SHARED(Locks::mutator_lock_); 102 103 template <bool kIsInstrumented> 104 ALWAYS_INLINE static String* AllocFromByteArray(Thread* self, int32_t byte_length, 105 Handle<ByteArray> array, int32_t offset, 106 int32_t high_byte, 107 gc::AllocatorType allocator_type) 108 REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); 109 110 template <bool kIsInstrumented> 111 ALWAYS_INLINE static String* AllocFromCharArray(Thread* self, int32_t count, 112 Handle<CharArray> array, int32_t offset, 113 gc::AllocatorType allocator_type) 114 REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); 115 116 template <bool kIsInstrumented> 117 ALWAYS_INLINE static String* AllocFromString(Thread* self, int32_t string_length, 118 Handle<String> string, int32_t offset, 119 gc::AllocatorType allocator_type) 120 REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); 121 122 template <bool kIsInstrumented> 123 ALWAYS_INLINE static String* AllocEmptyString(Thread* self, 124 gc::AllocatorType allocator_type) 125 REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); 126 127 static String* AllocFromStrings(Thread* self, Handle<String> string, Handle<String> string2) 128 REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); 129 130 static String* AllocFromUtf16(Thread* self, int32_t utf16_length, const uint16_t* utf16_data_in) 131 REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); 132 133 static String* AllocFromModifiedUtf8(Thread* self, const char* utf) 134 REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); 135 136 static String* AllocFromModifiedUtf8(Thread* self, int32_t utf16_length, 137 const char* utf8_data_in, int32_t utf8_length) 138 REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); 139 140 static String* AllocFromModifiedUtf8(Thread* self, int32_t utf16_length, const char* utf8_data_in) 141 REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); 142 143 // TODO: This is only used in the interpreter to compare against 144 // entries from a dex files constant pool (ArtField names). Should 145 // we unify this with Equals(const StringPiece&); ? 146 bool Equals(const char* modified_utf8) REQUIRES_SHARED(Locks::mutator_lock_); 147 148 // TODO: This is only used to compare DexCache.location with 149 // a dex_file's location (which is an std::string). Do we really 150 // need this in mirror::String just for that one usage ? 151 bool Equals(const StringPiece& modified_utf8) 152 REQUIRES_SHARED(Locks::mutator_lock_); 153 154 bool Equals(ObjPtr<String> that) REQUIRES_SHARED(Locks::mutator_lock_); 155 156 // Compare UTF-16 code point values not in a locale-sensitive manner 157 int Compare(int32_t utf16_length, const char* utf8_data_in); 158 159 // TODO: do we need this overload? give it a more intention-revealing name. 160 bool Equals(const uint16_t* that_chars, int32_t that_offset, 161 int32_t that_length) 162 REQUIRES_SHARED(Locks::mutator_lock_); 163 164 // Create a modified UTF-8 encoded std::string from a java/lang/String object. 165 std::string ToModifiedUtf8() REQUIRES_SHARED(Locks::mutator_lock_); 166 167 int32_t FastIndexOf(int32_t ch, int32_t start) REQUIRES_SHARED(Locks::mutator_lock_); 168 169 template <typename MemoryType> 170 int32_t FastIndexOf(MemoryType* chars, int32_t ch, int32_t start) 171 REQUIRES_SHARED(Locks::mutator_lock_); 172 173 int32_t CompareTo(ObjPtr<String> other) REQUIRES_SHARED(Locks::mutator_lock_); 174 175 CharArray* ToCharArray(Thread* self) REQUIRES_SHARED(Locks::mutator_lock_) 176 REQUIRES(!Roles::uninterruptible_); 177 178 void GetChars(int32_t start, int32_t end, Handle<CharArray> array, int32_t index) 179 REQUIRES_SHARED(Locks::mutator_lock_); 180 181 template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> IsCompressed()182 bool IsCompressed() REQUIRES_SHARED(Locks::mutator_lock_) { 183 return kUseStringCompression && IsCompressed(GetCount()); 184 } 185 186 bool IsValueNull() REQUIRES_SHARED(Locks::mutator_lock_); 187 188 template<typename MemoryType> 189 static bool AllASCII(const MemoryType* chars, const int length); 190 191 static bool DexFileStringAllASCII(const char* chars, const int length); 192 IsCompressed(int32_t count)193 ALWAYS_INLINE static bool IsCompressed(int32_t count) { 194 return GetCompressionFlagFromCount(count) == StringCompressionFlag::kCompressed; 195 } 196 GetCompressionFlagFromCount(int32_t count)197 ALWAYS_INLINE static StringCompressionFlag GetCompressionFlagFromCount(int32_t count) { 198 return kUseStringCompression 199 ? static_cast<StringCompressionFlag>(static_cast<uint32_t>(count) & 1u) 200 : StringCompressionFlag::kUncompressed; 201 } 202 GetLengthFromCount(int32_t count)203 ALWAYS_INLINE static int32_t GetLengthFromCount(int32_t count) { 204 return kUseStringCompression ? static_cast<int32_t>(static_cast<uint32_t>(count) >> 1) : count; 205 } 206 GetFlaggedCount(int32_t length,bool compressible)207 ALWAYS_INLINE static int32_t GetFlaggedCount(int32_t length, bool compressible) { 208 return kUseStringCompression 209 ? static_cast<int32_t>((static_cast<uint32_t>(length) << 1) | 210 (static_cast<uint32_t>(compressible 211 ? StringCompressionFlag::kCompressed 212 : StringCompressionFlag::kUncompressed))) 213 : length; 214 } 215 GetJavaLangString()216 static Class* GetJavaLangString() REQUIRES_SHARED(Locks::mutator_lock_) { 217 DCHECK(!java_lang_String_.IsNull()); 218 return java_lang_String_.Read(); 219 } 220 221 static void SetClass(ObjPtr<Class> java_lang_String) REQUIRES_SHARED(Locks::mutator_lock_); 222 static void ResetClass() REQUIRES_SHARED(Locks::mutator_lock_); 223 static void VisitRoots(RootVisitor* visitor) REQUIRES_SHARED(Locks::mutator_lock_); 224 225 // Returns a human-readable equivalent of 'descriptor'. So "I" would be "int", 226 // "[[I" would be "int[][]", "[Ljava/lang/String;" would be 227 // "java.lang.String[]", and so forth. 228 static std::string PrettyStringDescriptor(ObjPtr<mirror::String> descriptor) 229 REQUIRES_SHARED(Locks::mutator_lock_); 230 std::string PrettyStringDescriptor() 231 REQUIRES_SHARED(Locks::mutator_lock_); 232 233 private: IsASCII(uint16_t c)234 static constexpr bool IsASCII(uint16_t c) { 235 // Valid ASCII characters are in range 1..0x7f. Zero is not considered ASCII 236 // because it would complicate the detection of ASCII strings in Modified-UTF8. 237 return (c - 1u) < 0x7fu; 238 } 239 240 static bool AllASCIIExcept(const uint16_t* chars, int32_t length, uint16_t non_ascii); 241 SetHashCode(int32_t new_hash_code)242 void SetHashCode(int32_t new_hash_code) REQUIRES_SHARED(Locks::mutator_lock_) { 243 // Hash code is invariant so use non-transactional mode. Also disable check as we may run inside 244 // a transaction. 245 DCHECK_EQ(0, GetField32(OFFSET_OF_OBJECT_MEMBER(String, hash_code_))); 246 SetField32<false, false>(OFFSET_OF_OBJECT_MEMBER(String, hash_code_), new_hash_code); 247 } 248 249 template <bool kIsInstrumented, typename PreFenceVisitor> 250 ALWAYS_INLINE static String* Alloc(Thread* self, int32_t utf16_length_with_flag, 251 gc::AllocatorType allocator_type, 252 const PreFenceVisitor& pre_fence_visitor) 253 REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); 254 255 // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses". 256 257 // If string compression is enabled, count_ holds the StringCompressionFlag in the 258 // least significant bit and the length in the remaining bits, length = count_ >> 1. 259 int32_t count_; 260 261 uint32_t hash_code_; 262 263 // Compression of all-ASCII into 8-bit memory leads to usage one of these fields 264 union { 265 uint16_t value_[0]; 266 uint8_t value_compressed_[0]; 267 }; 268 269 static GcRoot<Class> java_lang_String_; 270 271 friend struct art::StringOffsets; // for verifying offset information 272 ART_FRIEND_TEST(art::StubTest, ReadBarrierForRoot); // For java_lang_String_. 273 274 DISALLOW_IMPLICIT_CONSTRUCTORS(String); 275 }; 276 277 } // namespace mirror 278 } // namespace art 279 280 #endif // ART_RUNTIME_MIRROR_STRING_H_ 281