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