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