1 /* 2 * Copyright (C) 2006, 2009 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 "StringImpl.h" 23 24 #if PLATFORM(CF) 25 26 #include <CoreFoundation/CoreFoundation.h> 27 #include <wtf/MainThread.h> 28 #include <wtf/PassRefPtr.h> 29 #include <wtf/Threading.h> 30 31 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) 32 #include <objc/objc-auto.h> 33 #endif 34 35 namespace WebCore { 36 37 namespace StringWrapperCFAllocator { 38 39 static StringImpl* currentString; 40 41 static const void* retain(const void* info) 42 { 43 return info; 44 } 45 46 static void release(const void*) 47 { 48 ASSERT_NOT_REACHED(); 49 } 50 51 static CFStringRef copyDescription(const void*) 52 { 53 return CFSTR("WebCore::String-based allocator"); 54 } 55 56 static void* allocate(CFIndex size, CFOptionFlags, void*) 57 { 58 StringImpl* underlyingString = 0; 59 if (isMainThread()) { 60 underlyingString = currentString; 61 if (underlyingString) { 62 currentString = 0; 63 underlyingString->ref(); // Balanced by call to deref in deallocate below. 64 } 65 } 66 StringImpl** header = static_cast<StringImpl**>(fastMalloc(sizeof(StringImpl*) + size)); 67 *header = underlyingString; 68 return header + 1; 69 } 70 71 static void* reallocate(void* pointer, CFIndex newSize, CFOptionFlags, void*) 72 { 73 size_t newAllocationSize = sizeof(StringImpl*) + newSize; 74 StringImpl** header = static_cast<StringImpl**>(pointer) - 1; 75 ASSERT(!*header); 76 header = static_cast<StringImpl**>(fastRealloc(header, newAllocationSize)); 77 return header + 1; 78 } 79 80 static void deallocateOnMainThread(void* headerPointer) 81 { 82 StringImpl** header = static_cast<StringImpl**>(headerPointer); 83 StringImpl* underlyingString = *header; 84 ASSERT(underlyingString); 85 underlyingString->deref(); // Balanced by call to ref in allocate above. 86 fastFree(header); 87 } 88 89 static void deallocate(void* pointer, void*) 90 { 91 StringImpl** header = static_cast<StringImpl**>(pointer) - 1; 92 StringImpl* underlyingString = *header; 93 if (!underlyingString) 94 fastFree(header); 95 else { 96 if (!isMainThread()) 97 callOnMainThread(deallocateOnMainThread, header); 98 else { 99 underlyingString->deref(); // Balanced by call to ref in allocate above. 100 fastFree(header); 101 } 102 } 103 } 104 105 static CFIndex preferredSize(CFIndex size, CFOptionFlags, void*) 106 { 107 // FIXME: If FastMalloc provided a "good size" callback, we'd want to use it here. 108 // Note that this optimization would help performance for strings created with the 109 // allocator that are mutable, and those typically are only created by callers who 110 // make a new string using the old string's allocator, such as some of the call 111 // sites in CFURL. 112 return size; 113 } 114 115 static CFAllocatorRef create() 116 { 117 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) 118 // Since garbage collection isn't compatible with custom allocators, don't use this at all when garbage collection is active. 119 if (objc_collectingEnabled()) 120 return 0; 121 #endif 122 CFAllocatorContext context = { 0, 0, retain, release, copyDescription, allocate, reallocate, deallocate, preferredSize }; 123 return CFAllocatorCreate(0, &context); 124 } 125 126 static CFAllocatorRef allocator() 127 { 128 static CFAllocatorRef allocator = create(); 129 return allocator; 130 } 131 132 } 133 134 CFStringRef StringImpl::createCFString() 135 { 136 CFAllocatorRef allocator = (m_length && isMainThread()) ? StringWrapperCFAllocator::allocator() : 0; 137 if (!allocator) 138 return CFStringCreateWithCharacters(0, reinterpret_cast<const UniChar*>(m_data), m_length); 139 140 // Put pointer to the StringImpl in a global so the allocator can store it with the CFString. 141 ASSERT(!StringWrapperCFAllocator::currentString); 142 StringWrapperCFAllocator::currentString = this; 143 144 CFStringRef string = CFStringCreateWithCharactersNoCopy(allocator, reinterpret_cast<const UniChar*>(m_data), m_length, kCFAllocatorNull); 145 146 // The allocator cleared the global when it read it, but also clear it here just in case. 147 ASSERT(!StringWrapperCFAllocator::currentString); 148 StringWrapperCFAllocator::currentString = 0; 149 150 return 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 // PLATFORM(CF) 163