1/* 2 * Copyright (C) 2006, 2009, 2012 Apple Inc. All rights reserved. 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Library General Public 6 * License as published by the Free Software Foundation; either 7 * version 2 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Library General Public License for more details. 13 * 14 * You should have received a copy of the GNU Library General Public License 15 * along with this library; see the file COPYING.LIB. If not, write to 16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 * Boston, MA 02110-1301, USA. 18 * 19 */ 20 21#include "config.h" 22#include <wtf/text/StringImpl.h> 23 24#if USE(CF) 25 26#include <CoreFoundation/CoreFoundation.h> 27#include <wtf/MainThread.h> 28#include <wtf/PassRefPtr.h> 29#include <wtf/RetainPtr.h> 30#include <wtf/Threading.h> 31 32#if PLATFORM(MAC) 33#include <objc/objc-auto.h> 34#endif 35 36static inline bool garbageCollectionEnabled() 37{ 38#if PLATFORM(MAC) 39 return objc_collectingEnabled(); 40#else 41 return false; 42#endif 43} 44 45namespace WTF { 46 47namespace StringWrapperCFAllocator { 48 49 static StringImpl* currentString; 50 51 static const void* retain(const void* info) 52 { 53 return info; 54 } 55 56 NO_RETURN_DUE_TO_ASSERT 57 static void release(const void*) 58 { 59 ASSERT_NOT_REACHED(); 60 } 61 62 static CFStringRef copyDescription(const void*) 63 { 64 return CFSTR("WTF::String-based allocator"); 65 } 66 67 static void* allocate(CFIndex size, CFOptionFlags, void*) 68 { 69 StringImpl* underlyingString = 0; 70 if (isMainThread()) { 71 underlyingString = currentString; 72 if (underlyingString) { 73 currentString = 0; 74 underlyingString->ref(); // Balanced by call to deref in deallocate below. 75 } 76 } 77 StringImpl** header = static_cast<StringImpl**>(fastMalloc(sizeof(StringImpl*) + size)); 78 *header = underlyingString; 79 return header + 1; 80 } 81 82 static void* reallocate(void* pointer, CFIndex newSize, CFOptionFlags, void*) 83 { 84 size_t newAllocationSize = sizeof(StringImpl*) + newSize; 85 StringImpl** header = static_cast<StringImpl**>(pointer) - 1; 86 ASSERT(!*header); 87 header = static_cast<StringImpl**>(fastRealloc(header, newAllocationSize)); 88 return header + 1; 89 } 90 91 static void deallocateOnMainThread(void* headerPointer) 92 { 93 StringImpl** header = static_cast<StringImpl**>(headerPointer); 94 StringImpl* underlyingString = *header; 95 ASSERT(underlyingString); 96 underlyingString->deref(); // Balanced by call to ref in allocate above. 97 fastFree(header); 98 } 99 100 static void deallocate(void* pointer, void*) 101 { 102 StringImpl** header = static_cast<StringImpl**>(pointer) - 1; 103 StringImpl* underlyingString = *header; 104 if (!underlyingString) 105 fastFree(header); 106 else { 107 if (!isMainThread()) 108 callOnMainThread(deallocateOnMainThread, header); 109 else { 110 underlyingString->deref(); // Balanced by call to ref in allocate above. 111 fastFree(header); 112 } 113 } 114 } 115 116 static CFIndex preferredSize(CFIndex size, CFOptionFlags, void*) 117 { 118 // FIXME: If FastMalloc provided a "good size" callback, we'd want to use it here. 119 // Note that this optimization would help performance for strings created with the 120 // allocator that are mutable, and those typically are only created by callers who 121 // make a new string using the old string's allocator, such as some of the call 122 // sites in CFURL. 123 return size; 124 } 125 126 static CFAllocatorRef create() 127 { 128 ASSERT(!garbageCollectionEnabled()); 129 CFAllocatorContext context = { 0, 0, retain, release, copyDescription, allocate, reallocate, deallocate, preferredSize }; 130 return CFAllocatorCreate(0, &context); 131 } 132 133 static CFAllocatorRef allocator() 134 { 135 static CFAllocatorRef allocator = create(); 136 return allocator; 137 } 138 139} 140 141RetainPtr<CFStringRef> StringImpl::createCFString() 142{ 143 // Since garbage collection isn't compatible with custom allocators, we 144 // can't use the NoCopy variants of CFStringCreate*() when GC is enabled. 145 if (!m_length || !isMainThread() || garbageCollectionEnabled()) { 146 if (is8Bit()) 147 return adoptCF(CFStringCreateWithBytes(0, reinterpret_cast<const UInt8*>(characters8()), m_length, kCFStringEncodingISOLatin1, false)); 148 return adoptCF(CFStringCreateWithCharacters(0, reinterpret_cast<const UniChar*>(characters16()), m_length)); 149 } 150 CFAllocatorRef allocator = StringWrapperCFAllocator::allocator(); 151 152 // Put pointer to the StringImpl in a global so the allocator can store it with the CFString. 153 ASSERT(!StringWrapperCFAllocator::currentString); 154 StringWrapperCFAllocator::currentString = this; 155 156 CFStringRef string; 157 if (is8Bit()) 158 string = CFStringCreateWithBytesNoCopy(allocator, reinterpret_cast<const UInt8*>(characters8()), m_length, kCFStringEncodingISOLatin1, false, kCFAllocatorNull); 159 else 160 string = CFStringCreateWithCharactersNoCopy(allocator, reinterpret_cast<const UniChar*>(characters16()), m_length, kCFAllocatorNull); 161 // CoreFoundation might not have to allocate anything, we clear currentString in case we did not execute allocate(). 162 StringWrapperCFAllocator::currentString = 0; 163 164 return adoptCF(string); 165} 166 167// On StringImpl creation we could check if the allocator is the StringWrapperCFAllocator. 168// If it is, then we could find the original StringImpl and just return that. But to 169// do that we'd have to compute the offset from CFStringRef to the allocated block; 170// the CFStringRef is *not* at the start of an allocated block. Testing shows 1000x 171// more calls to createCFString than calls to the create functions with the appropriate 172// allocator, so it's probably not urgent optimize that case. 173 174} 175 176#endif // USE(CF) 177