| // Copyright 2017 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_BINDINGS_STRING_RESOURCE_H_ |
| #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_BINDINGS_STRING_RESOURCE_H_ |
| |
| #include "base/macros.h" |
| #include "third_party/blink/renderer/platform/bindings/parkable_string.h" |
| #include "third_party/blink/renderer/platform/platform_export.h" |
| #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" |
| #include "third_party/blink/renderer/platform/wtf/text/atomic_string.h" |
| #include "third_party/blink/renderer/platform/wtf/threading.h" |
| #include "v8/include/v8.h" |
| |
| namespace blink { |
| |
| // StringResource is a helper class for V8ExternalString. It is used |
| // to manage the life-cycle of the underlying buffer of the external string. |
| class StringResourceBase { |
| USING_FAST_MALLOC(StringResourceBase); |
| |
| public: |
| explicit StringResourceBase(const String& string) : plain_string_(string) { |
| #if DCHECK_IS_ON() |
| thread_id_ = WTF::CurrentThread(); |
| #endif |
| DCHECK(!string.IsNull()); |
| v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory( |
| string.CharactersSizeInBytes()); |
| } |
| |
| explicit StringResourceBase(const AtomicString& string) |
| : plain_string_(string.GetString()), atomic_string_(string) { |
| #if DCHECK_IS_ON() |
| thread_id_ = WTF::CurrentThread(); |
| #endif |
| DCHECK(!string.IsNull()); |
| v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory( |
| string.CharactersSizeInBytes()); |
| } |
| |
| explicit StringResourceBase(const ParkableString& string) |
| : parkable_string_(string) { |
| #if DCHECK_IS_ON() |
| thread_id_ = WTF::CurrentThread(); |
| #endif |
| // TODO(lizeb): This is only true without compression. |
| DCHECK(!string.IsNull()); |
| v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory( |
| string.CharactersSizeInBytes()); |
| } |
| |
| virtual ~StringResourceBase() { |
| #if DCHECK_IS_ON() |
| DCHECK(thread_id_ == WTF::CurrentThread()); |
| #endif |
| int64_t reduced_external_memory = plain_string_.CharactersSizeInBytes(); |
| if (plain_string_.Impl() != atomic_string_.Impl() && |
| !atomic_string_.IsNull()) |
| reduced_external_memory += atomic_string_.CharactersSizeInBytes(); |
| v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory( |
| -reduced_external_memory); |
| } |
| |
| String GetWTFString() { |
| if (!parkable_string_.IsNull()) { |
| DCHECK(plain_string_.IsNull()); |
| DCHECK(atomic_string_.IsNull()); |
| return parkable_string_.ToString(); |
| } |
| return plain_string_; |
| } |
| |
| AtomicString GetAtomicString() { |
| #if DCHECK_IS_ON() |
| DCHECK(thread_id_ == WTF::CurrentThread()); |
| #endif |
| if (!parkable_string_.IsNull()) { |
| DCHECK(plain_string_.IsNull()); |
| DCHECK(atomic_string_.IsNull()); |
| return AtomicString(parkable_string_.ToString()); |
| } |
| if (atomic_string_.IsNull()) { |
| atomic_string_ = AtomicString(plain_string_); |
| DCHECK(!atomic_string_.IsNull()); |
| if (plain_string_.Impl() != atomic_string_.Impl()) { |
| v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory( |
| atomic_string_.CharactersSizeInBytes()); |
| } |
| } |
| return atomic_string_; |
| } |
| |
| protected: |
| // A shallow copy of the string. Keeps the string buffer alive until the V8 |
| // engine garbage collects it. |
| String plain_string_; |
| // If this string is atomic or has been made atomic earlier the |
| // atomic string is held here. In the case where the string starts |
| // off non-atomic and becomes atomic later it is necessary to keep |
| // the original string alive because v8 may keep derived pointers |
| // into that string. |
| AtomicString atomic_string_; |
| // If this string is parkable, its value is held here, and the other |
| // members above are null. |
| ParkableString parkable_string_; |
| |
| private: |
| #if DCHECK_IS_ON() |
| base::PlatformThreadId thread_id_; |
| #endif |
| |
| DISALLOW_COPY_AND_ASSIGN(StringResourceBase); |
| }; |
| |
| // Even though StringResource{8,16}Base are effectively empty in release mode, |
| // they are needed as they serve as a common ancestor to Parkable and regular |
| // strings. |
| // |
| // See the comment in |ToBlinkString()|'s implementation for the rationale. |
| class StringResource16Base : public StringResourceBase, |
| public v8::String::ExternalStringResource { |
| public: |
| explicit StringResource16Base(const String& string) |
| : StringResourceBase(string) { |
| DCHECK(!string.Is8Bit()); |
| } |
| |
| explicit StringResource16Base(const AtomicString& string) |
| : StringResourceBase(string) { |
| DCHECK(!string.Is8Bit()); |
| } |
| |
| explicit StringResource16Base(const ParkableString& parkable_string) |
| : StringResourceBase(parkable_string) { |
| DCHECK(!parkable_string.Is8Bit()); |
| } |
| |
| DISALLOW_COPY_AND_ASSIGN(StringResource16Base); |
| }; |
| |
| class StringResource16 final : public StringResource16Base { |
| public: |
| explicit StringResource16(const String& string) |
| : StringResource16Base(string) {} |
| |
| explicit StringResource16(const AtomicString& string) |
| : StringResource16Base(string) {} |
| |
| size_t length() const override { return plain_string_.Impl()->length(); } |
| const uint16_t* data() const override { |
| return reinterpret_cast<const uint16_t*>( |
| plain_string_.Impl()->Characters16()); |
| } |
| |
| DISALLOW_COPY_AND_ASSIGN(StringResource16); |
| }; |
| |
| class ParkableStringResource16 final : public StringResource16Base { |
| public: |
| explicit ParkableStringResource16(const ParkableString& string) |
| : StringResource16Base(string) {} |
| |
| bool IsCacheable() const override { |
| return !parkable_string_.may_be_parked(); |
| } |
| |
| void Lock() const override { parkable_string_.Lock(); } |
| |
| void Unlock() const override { parkable_string_.Unlock(); } |
| |
| size_t length() const override { return parkable_string_.length(); } |
| |
| const uint16_t* data() const override { |
| return reinterpret_cast<const uint16_t*>(parkable_string_.Characters16()); |
| } |
| |
| DISALLOW_COPY_AND_ASSIGN(ParkableStringResource16); |
| }; |
| |
| class StringResource8Base : public StringResourceBase, |
| public v8::String::ExternalOneByteStringResource { |
| public: |
| explicit StringResource8Base(const String& string) |
| : StringResourceBase(string) { |
| DCHECK(string.Is8Bit()); |
| } |
| |
| explicit StringResource8Base(const AtomicString& string) |
| : StringResourceBase(string) { |
| DCHECK(string.Is8Bit()); |
| } |
| |
| explicit StringResource8Base(const ParkableString& parkable_string) |
| : StringResourceBase(parkable_string) { |
| DCHECK(parkable_string.Is8Bit()); |
| } |
| |
| DISALLOW_COPY_AND_ASSIGN(StringResource8Base); |
| }; |
| |
| class StringResource8 final : public StringResource8Base { |
| public: |
| explicit StringResource8(const String& string) |
| : StringResource8Base(string) {} |
| |
| explicit StringResource8(const AtomicString& string) |
| : StringResource8Base(string) {} |
| |
| size_t length() const override { return plain_string_.Impl()->length(); } |
| const char* data() const override { |
| return reinterpret_cast<const char*>(plain_string_.Impl()->Characters8()); |
| } |
| |
| DISALLOW_COPY_AND_ASSIGN(StringResource8); |
| }; |
| |
| class ParkableStringResource8 final : public StringResource8Base { |
| public: |
| explicit ParkableStringResource8(const ParkableString& string) |
| : StringResource8Base(string) {} |
| |
| bool IsCacheable() const override { |
| return !parkable_string_.may_be_parked(); |
| } |
| |
| void Lock() const override { parkable_string_.Lock(); } |
| |
| void Unlock() const override { parkable_string_.Unlock(); } |
| |
| size_t length() const override { return parkable_string_.length(); } |
| |
| const char* data() const override { |
| return reinterpret_cast<const char*>(parkable_string_.Characters8()); |
| } |
| |
| DISALLOW_COPY_AND_ASSIGN(ParkableStringResource8); |
| }; |
| |
| enum ExternalMode { kExternalize, kDoNotExternalize }; |
| |
| template <typename StringType> |
| PLATFORM_EXPORT StringType ToBlinkString(v8::Local<v8::String>, ExternalMode); |
| |
| // This method is similar to ToBlinkString() except when the underlying |
| // v8::String cannot be externalized (often happens with short strings like "id" |
| // on 64-bit platforms where V8 uses pointer compression) the v8::String is |
| // copied into the given StringView::StackBackingStore which avoids creating an |
| // AtomicString unnecessarily. |
| PLATFORM_EXPORT StringView ToBlinkStringView(v8::Local<v8::String>, |
| StringView::StackBackingStore&, |
| ExternalMode); |
| |
| PLATFORM_EXPORT String ToBlinkString(int value); |
| |
| // The returned StringView is guaranteed to be valid as long as `backing_store` |
| // and `v8_string` are alive. |
| PLATFORM_EXPORT StringView |
| ToBlinkStringView(v8::Local<v8::String> v8_string, |
| StringView::StackBackingStore& backing_store, |
| ExternalMode external); |
| |
| } // namespace blink |
| |
| #endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_BINDINGS_STRING_RESOURCE_H_ |