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 "wtf/MainThread.h" 27 #include "wtf/PassRefPtr.h" 28 #include "wtf/RetainPtr.h" 29 #include "wtf/Threading.h" 30 #include <CoreFoundation/CoreFoundation.h> 31 32 namespace WTF { 33 34 namespace StringWrapperCFAllocator { 35 36 static StringImpl* currentString; 37 38 static const void* retain(const void* info) 39 { 40 return info; 41 } 42 43 NO_RETURN_DUE_TO_ASSERT 44 static void release(const void*) 45 { 46 ASSERT_NOT_REACHED(); 47 } 48 49 static CFStringRef copyDescription(const void*) 50 { 51 return CFSTR("WTF::String-based allocator"); 52 } 53 54 static void* allocate(CFIndex size, CFOptionFlags, void*) 55 { 56 StringImpl* underlyingString = 0; 57 if (isMainThread()) { 58 underlyingString = currentString; 59 if (underlyingString) { 60 currentString = 0; 61 underlyingString->ref(); // Balanced by call to deref in deallocate below. 62 } 63 } 64 StringImpl** header = static_cast<StringImpl**>(fastMalloc(sizeof(StringImpl*) + size)); 65 *header = underlyingString; 66 return header + 1; 67 } 68 69 static void* reallocate(void* pointer, CFIndex newSize, CFOptionFlags, void*) 70 { 71 size_t newAllocationSize = sizeof(StringImpl*) + newSize; 72 StringImpl** header = static_cast<StringImpl**>(pointer) - 1; 73 ASSERT(!*header); 74 header = static_cast<StringImpl**>(fastRealloc(header, newAllocationSize)); 75 return header + 1; 76 } 77 78 static void deallocateOnMainThread(void* headerPointer) 79 { 80 StringImpl** header = static_cast<StringImpl**>(headerPointer); 81 StringImpl* underlyingString = *header; 82 ASSERT(underlyingString); 83 underlyingString->deref(); // Balanced by call to ref in allocate above. 84 fastFree(header); 85 } 86 87 static void deallocate(void* pointer, void*) 88 { 89 StringImpl** header = static_cast<StringImpl**>(pointer) - 1; 90 StringImpl* underlyingString = *header; 91 if (!underlyingString) { 92 fastFree(header); 93 } else { 94 if (!isMainThread()) { 95 callOnMainThread(deallocateOnMainThread, header); 96 } else { 97 underlyingString->deref(); // Balanced by call to ref in allocate above. 98 fastFree(header); 99 } 100 } 101 } 102 103 static CFIndex preferredSize(CFIndex size, CFOptionFlags, void*) 104 { 105 // FIXME: If FastMalloc provided a "good size" callback, we'd want to use it here. 106 // Note that this optimization would help performance for strings created with the 107 // allocator that are mutable, and those typically are only created by callers who 108 // make a new string using the old string's allocator, such as some of the call 109 // sites in CFURL. 110 return size; 111 } 112 113 static CFAllocatorRef create() 114 { 115 CFAllocatorContext context = { 0, 0, retain, release, copyDescription, allocate, reallocate, deallocate, preferredSize }; 116 return CFAllocatorCreate(0, &context); 117 } 118 119 static CFAllocatorRef allocator() 120 { 121 static CFAllocatorRef allocator = create(); 122 return allocator; 123 } 124 125 } 126 127 RetainPtr<CFStringRef> StringImpl::createCFString() 128 { 129 // Since garbage collection isn't compatible with custom allocators, we 130 // can't use the NoCopy variants of CFStringCreate*() when GC is enabled. 131 if (!m_length || !isMainThread()) { 132 if (is8Bit()) 133 return adoptCF(CFStringCreateWithBytes(0, reinterpret_cast<const UInt8*>(characters8()), m_length, kCFStringEncodingISOLatin1, false)); 134 return adoptCF(CFStringCreateWithCharacters(0, reinterpret_cast<const UniChar*>(characters16()), m_length)); 135 } 136 CFAllocatorRef allocator = StringWrapperCFAllocator::allocator(); 137 138 // Put pointer to the StringImpl in a global so the allocator can store it with the CFString. 139 ASSERT(!StringWrapperCFAllocator::currentString); 140 StringWrapperCFAllocator::currentString = this; 141 142 CFStringRef string; 143 if (is8Bit()) 144 string = CFStringCreateWithBytesNoCopy(allocator, reinterpret_cast<const UInt8*>(characters8()), m_length, kCFStringEncodingISOLatin1, false, kCFAllocatorNull); 145 else 146 string = CFStringCreateWithCharactersNoCopy(allocator, reinterpret_cast<const UniChar*>(characters16()), m_length, kCFAllocatorNull); 147 // CoreFoundation might not have to allocate anything, we clear currentString in case we did not execute allocate(). 148 StringWrapperCFAllocator::currentString = 0; 149 150 return adoptCF(string); 151 } 152 153 // On StringImpl creation we could check if the allocator is the StringWrapperCFAllocator. 154 // If it is, then we could find the original StringImpl and just return that. But to 155 // do that we'd have to compute the offset from CFStringRef to the allocated block; 156 // the CFStringRef is *not* at the start of an allocated block. Testing shows 1000x 157 // more calls to createCFString than calls to the create functions with the appropriate 158 // allocator, so it's probably not urgent optimize that case. 159 160 } 161 162 #endif // USE(CF) 163