blob: 6fde0556d857ce32a5062e178f2c4007fa4b36dc [file] [log] [blame]
/*
* Copyright (C) 2018 Apple 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. ``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
* 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 "config.h"
#include "ThreadLocalCache.h"
#include "ThreadLocalCacheInlines.h"
#include "ThreadLocalCacheLayout.h"
#include <wtf/StdLibExtras.h>
namespace JSC {
RefPtr<ThreadLocalCache> ThreadLocalCache::create(Heap& heap)
{
return adoptRef(new ThreadLocalCache(heap));
}
ThreadLocalCache::ThreadLocalCache(Heap& heap)
: m_heap(heap)
{
m_data = allocateData();
}
ThreadLocalCache::~ThreadLocalCache()
{
destroyData(m_data);
}
ThreadLocalCache::Data* ThreadLocalCache::allocateData()
{
size_t oldSize = m_data ? m_data->size : 0;
ThreadLocalCacheLayout::Snapshot layout = m_heap.threadLocalCacheLayout().snapshot();
Data* result = static_cast<Data*>(fastMalloc(OBJECT_OFFSETOF(Data, allocator) + layout.size));
result->size = layout.size;
result->cache = this;
for (size_t offset = 0; offset < oldSize; offset += sizeof(LocalAllocator))
new (&allocator(*result, offset)) LocalAllocator(WTFMove(allocator(*m_data, offset)));
for (size_t offset = oldSize; offset < layout.size; offset += sizeof(LocalAllocator))
new (&allocator(*result, offset)) LocalAllocator(this, layout.directories[offset / sizeof(LocalAllocator)]);
return result;
}
void ThreadLocalCache::destroyData(Data* data)
{
for (size_t offset = 0; offset < data->size; offset += sizeof(LocalAllocator))
allocator(*data, offset).~LocalAllocator();
fastFree(data);
}
void ThreadLocalCache::installSlow(VM& vm, RefPtr<ThreadLocalCache>* previous)
{
#if USE(FAST_TLS_FOR_TLC)
static std::once_flag onceFlag;
std::call_once(
onceFlag,
[] () {
pthread_key_init_np(tlsKey, destructor);
});
#endif
ref();
if (ThreadLocalCache::Data* oldCacheData = getImpl(vm)) {
ThreadLocalCache* oldCache = oldCacheData->cache;
if (previous)
*previous = adoptRef(oldCache);
else
oldCache->deref();
}
installData(vm, m_data);
}
void ThreadLocalCache::installData(VM& vm, Data* data)
{
#if USE(FAST_TLS_FOR_TLC)
UNUSED_PARAM(vm);
_pthread_setspecific_direct(tlsKey, data);
#else
vm.threadLocalCacheData = data;
#endif
}
LocalAllocator& ThreadLocalCache::allocatorSlow(VM& vm, size_t offset)
{
Data* oldData = m_data;
m_data = allocateData();
destroyData(oldData);
installData(vm, m_data);
RELEASE_ASSERT(offset < m_data->size);
return allocator(*m_data, offset);
}
void ThreadLocalCache::destructor(void* arg)
{
if (!arg)
return;
Data* data = static_cast<Data*>(arg);
data->cache->deref();
}
} // namespace JSC