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