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