blob: b19c1719b4f7f683c77678d62c4c4d609859b725 [file] [log] [blame]
/*
* Copyright (C) 2009 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "third_party/blink/renderer/platform/bindings/v8_value_cache.h"
#include <utility>
#include "third_party/blink/renderer/platform/bindings/runtime_call_stats.h"
#include "third_party/blink/renderer/platform/bindings/v8_binding.h"
#include "third_party/blink/renderer/platform/wtf/text/string_hash.h"
namespace blink {
StringCacheMapTraits::MapType* StringCacheMapTraits::MapFromWeakCallbackInfo(
const v8::WeakCallbackInfo<WeakCallbackDataType>& data) {
return &(V8PerIsolateData::From(data.GetIsolate())
->GetStringCache()
->string_cache_);
}
void StringCacheMapTraits::Dispose(v8::Isolate* isolate,
v8::Global<v8::String> value,
StringImpl* key) {
V8PerIsolateData::From(isolate)->GetStringCache()->InvalidateLastString();
key->Release();
}
void StringCacheMapTraits::DisposeWeak(
const v8::WeakCallbackInfo<WeakCallbackDataType>& data) {
V8PerIsolateData::From(data.GetIsolate())
->GetStringCache()
->InvalidateLastString();
data.GetParameter()->Release();
}
void StringCacheMapTraits::OnWeakCallback(
const v8::WeakCallbackInfo<WeakCallbackDataType>& data) {
V8PerIsolateData::From(data.GetIsolate())
->GetStringCache()
->InvalidateLastString();
}
ParkableStringCacheMapTraits::MapType*
ParkableStringCacheMapTraits::MapFromWeakCallbackInfo(
const v8::WeakCallbackInfo<WeakCallbackDataType>& data) {
return &(V8PerIsolateData::From(data.GetIsolate())
->GetStringCache()
->parkable_string_cache_);
}
void ParkableStringCacheMapTraits::Dispose(v8::Isolate* isolate,
v8::Global<v8::String> value,
ParkableStringImpl* key) {
key->Release();
}
void ParkableStringCacheMapTraits::DisposeWeak(
const v8::WeakCallbackInfo<WeakCallbackDataType>& data) {
data.GetParameter()->Release();
}
void ParkableStringCacheMapTraits::OnWeakCallback(
const v8::WeakCallbackInfo<WeakCallbackDataType>& data) {}
void StringCache::Dispose() {
// The MapType::Dispose callback calls StringCache::InvalidateLastString,
// which will only work while the destructor has not yet finished. Thus,
// we need to clear the map before the destructor has completed.
string_cache_.Clear();
}
static v8::Local<v8::String> MakeExternalString(v8::Isolate* isolate,
const String& string) {
if (string.Is8Bit()) {
StringResource8* string_resource = new StringResource8(string);
v8::Local<v8::String> new_string;
if (!v8::String::NewExternalOneByte(isolate, string_resource)
.ToLocal(&new_string)) {
delete string_resource;
return v8::String::Empty(isolate);
}
return new_string;
}
StringResource16* string_resource = new StringResource16(string);
v8::Local<v8::String> new_string;
if (!v8::String::NewExternalTwoByte(isolate, string_resource)
.ToLocal(&new_string)) {
delete string_resource;
return v8::String::Empty(isolate);
}
return new_string;
}
static v8::Local<v8::String> MakeExternalString(v8::Isolate* isolate,
const ParkableString& string) {
if (string.Is8Bit()) {
auto* string_resource = new ParkableStringResource8(string);
v8::Local<v8::String> new_string;
if (!v8::String::NewExternalOneByte(isolate, string_resource)
.ToLocal(&new_string)) {
delete string_resource;
return v8::String::Empty(isolate);
}
return new_string;
}
auto* string_resource = new ParkableStringResource16(string);
v8::Local<v8::String> new_string;
if (!v8::String::NewExternalTwoByte(isolate, string_resource)
.ToLocal(&new_string)) {
delete string_resource;
return v8::String::Empty(isolate);
}
return new_string;
}
v8::Local<v8::String> StringCache::V8ExternalStringSlow(
v8::Isolate* isolate,
StringImpl* string_impl) {
RUNTIME_CALL_TIMER_SCOPE(isolate,
RuntimeCallStats::CounterId::kV8ExternalStringSlow);
if (!string_impl->length())
return v8::String::Empty(isolate);
StringCacheMapTraits::MapType::PersistentValueReference cached_v8_string =
string_cache_.GetReference(string_impl);
if (!cached_v8_string.IsEmpty()) {
last_string_impl_ = string_impl;
last_v8_string_ = cached_v8_string;
return last_v8_string_.NewLocal(isolate);
}
return CreateStringAndInsertIntoCache(isolate, string_impl);
}
v8::Local<v8::String> StringCache::V8ExternalString(
v8::Isolate* isolate,
const ParkableString& string) {
if (!string.length())
return v8::String::Empty(isolate);
ParkableStringCacheMapTraits::MapType::PersistentValueReference
cached_v8_string = parkable_string_cache_.GetReference(string.Impl());
if (!cached_v8_string.IsEmpty()) {
return cached_v8_string.NewLocal(isolate);
}
return CreateStringAndInsertIntoCache(isolate, string);
}
void StringCache::SetReturnValueFromStringSlow(
v8::ReturnValue<v8::Value> return_value,
StringImpl* string_impl) {
RUNTIME_CALL_TIMER_SCOPE(
return_value.GetIsolate(),
RuntimeCallStats::CounterId::kSetReturnValueFromStringSlow);
if (!string_impl->length()) {
return_value.SetEmptyString();
return;
}
StringCacheMapTraits::MapType::PersistentValueReference cached_v8_string =
string_cache_.GetReference(string_impl);
if (!cached_v8_string.IsEmpty()) {
last_string_impl_ = string_impl;
last_v8_string_ = cached_v8_string;
last_v8_string_.SetReturnValue(return_value);
return;
}
return_value.Set(
CreateStringAndInsertIntoCache(return_value.GetIsolate(), string_impl));
}
v8::Local<v8::String> StringCache::CreateStringAndInsertIntoCache(
v8::Isolate* isolate,
StringImpl* string_impl) {
DCHECK(!string_cache_.Contains(string_impl));
DCHECK(string_impl->length());
v8::Local<v8::String> new_string =
MakeExternalString(isolate, String(string_impl));
DCHECK(!new_string.IsEmpty());
DCHECK(new_string->Length());
v8::UniquePersistent<v8::String> wrapper(isolate, new_string);
string_impl->AddRef();
string_cache_.Set(string_impl, std::move(wrapper), &last_v8_string_);
last_string_impl_ = string_impl;
return new_string;
}
v8::Local<v8::String> StringCache::CreateStringAndInsertIntoCache(
v8::Isolate* isolate,
const ParkableString& string) {
ParkableStringImpl* string_impl = string.Impl();
DCHECK(!parkable_string_cache_.Contains(string_impl));
DCHECK(string_impl->length());
v8::Local<v8::String> new_string =
MakeExternalString(isolate, ParkableString(string));
DCHECK(!new_string.IsEmpty());
DCHECK(new_string->Length());
v8::UniquePersistent<v8::String> wrapper(isolate, new_string);
string_impl->AddRef();
// ParkableStringImpl objects are not cache in |string_cache_| or
// |last_string_impl_|.
ParkableStringCacheMapTraits::MapType::PersistentValueReference unused;
parkable_string_cache_.Set(string_impl, std::move(wrapper), &unused);
return new_string;
}
void StringCache::InvalidateLastString() {
last_string_impl_ = nullptr;
last_v8_string_.Reset();
}
} // namespace blink