blob: 7874392294e0cc188983ea710b5aff17fa432d1b [file] [log] [blame]
// 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.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()
WTF::ThreadIdentifier 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);
PLATFORM_EXPORT String ToBlinkString(int value);
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_BINDINGS_STRING_RESOURCE_H_