Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / platform / SharedBuffer.cpp
1 /*
2  * Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
3  * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include "config.h"
28 #include "platform/SharedBuffer.h"
29
30 #include "wtf/unicode/Unicode.h"
31 #include "wtf/unicode/UTF8.h"
32
33 #undef SHARED_BUFFER_STATS
34
35 #ifdef SHARED_BUFFER_STATS
36 #include "wtf/DataLog.h"
37 #include "wtf/MainThread.h"
38 #endif
39
40 using namespace std;
41
42 namespace WebCore {
43
44 static const unsigned segmentSize = 0x1000;
45 static const unsigned segmentPositionMask = 0x0FFF;
46
47 static inline unsigned segmentIndex(unsigned position)
48 {
49     return position / segmentSize;
50 }
51
52 static inline unsigned offsetInSegment(unsigned position)
53 {
54     return position & segmentPositionMask;
55 }
56
57 static inline char* allocateSegment()
58 {
59     return static_cast<char*>(fastMalloc(segmentSize));
60 }
61
62 static inline void freeSegment(char* p)
63 {
64     fastFree(p);
65 }
66
67 #ifdef SHARED_BUFFER_STATS
68
69 static Mutex& statsMutex()
70 {
71     DEFINE_STATIC_LOCAL(Mutex, mutex, ());
72     return mutex;
73 }
74
75 static HashSet<SharedBuffer*>& liveBuffers()
76 {
77     DEFINE_STATIC_LOCAL(HashSet<SharedBuffer*>, buffers, ());
78     return buffers;
79 }
80
81 static bool sizeComparator(SharedBuffer* a, SharedBuffer* b)
82 {
83     return a->size() > b->size();
84 }
85
86 static CString snippetForBuffer(SharedBuffer* sharedBuffer)
87 {
88     const unsigned kMaxSnippetLength = 64;
89     char* snippet = 0;
90     unsigned snippetLength = std::min(sharedBuffer->size(), kMaxSnippetLength);
91     CString result = CString::newUninitialized(snippetLength, snippet);
92
93     const char* segment;
94     unsigned offset = 0;
95     while (unsigned segmentLength = sharedBuffer->getSomeData(segment, offset)) {
96         unsigned length = std::min(segmentLength, snippetLength - offset);
97         memcpy(snippet + offset, segment, length);
98         offset += segmentLength;
99         if (offset >= snippetLength)
100             break;
101     }
102
103     for (unsigned i = 0; i < snippetLength; ++i) {
104         if (!isASCIIPrintable(snippet[i]))
105             snippet[i] = '?';
106     }
107
108     return result;
109 }
110
111 static void printStats(void*)
112 {
113     MutexLocker locker(statsMutex());
114     Vector<SharedBuffer*> buffers;
115     for (HashSet<SharedBuffer*>::const_iterator iter = liveBuffers().begin(); iter != liveBuffers().end(); ++iter)
116         buffers.append(*iter);
117     std::sort(buffers.begin(), buffers.end(), sizeComparator);
118
119     dataLogF("---- Shared Buffer Stats ----\n");
120     for (size_t i = 0; i < buffers.size() && i < 64; ++i) {
121         CString snippet = snippetForBuffer(buffers[i]);
122         dataLogF("Buffer size=%8u %s\n", buffers[i]->size(), snippet.data());
123     }
124 }
125
126 static void didCreateSharedBuffer(SharedBuffer* buffer)
127 {
128     MutexLocker locker(statsMutex());
129     liveBuffers().add(buffer);
130
131     callOnMainThread(printStats, 0);
132 }
133
134 static void willDestroySharedBuffer(SharedBuffer* buffer)
135 {
136     MutexLocker locker(statsMutex());
137     liveBuffers().remove(buffer);
138 }
139
140 #endif
141
142 SharedBuffer::SharedBuffer()
143     : m_size(0)
144     , m_buffer(PurgeableVector::NotPurgeable)
145 {
146 #ifdef SHARED_BUFFER_STATS
147     didCreateSharedBuffer(this);
148 #endif
149 }
150
151 SharedBuffer::SharedBuffer(size_t size)
152     : m_size(size)
153     , m_buffer(PurgeableVector::NotPurgeable)
154 {
155     m_buffer.reserveCapacity(size);
156     m_buffer.grow(size);
157 #ifdef SHARED_BUFFER_STATS
158     didCreateSharedBuffer(this);
159 #endif
160 }
161
162 SharedBuffer::SharedBuffer(const char* data, int size)
163     : m_size(0)
164     , m_buffer(PurgeableVector::NotPurgeable)
165 {
166     // FIXME: Use unsigned consistently, and check for invalid casts when calling into SharedBuffer from other code.
167     if (size < 0)
168         CRASH();
169
170     append(data, size);
171
172 #ifdef SHARED_BUFFER_STATS
173     didCreateSharedBuffer(this);
174 #endif
175 }
176
177 SharedBuffer::SharedBuffer(const char* data, int size, PurgeableVector::PurgeableOption purgeable)
178     : m_size(0)
179     , m_buffer(purgeable)
180 {
181     // FIXME: Use unsigned consistently, and check for invalid casts when calling into SharedBuffer from other code.
182     if (size < 0)
183         CRASH();
184
185     append(data, size);
186
187 #ifdef SHARED_BUFFER_STATS
188     didCreateSharedBuffer(this);
189 #endif
190 }
191
192 SharedBuffer::SharedBuffer(const unsigned char* data, int size)
193     : m_size(0)
194     , m_buffer(PurgeableVector::NotPurgeable)
195 {
196     // FIXME: Use unsigned consistently, and check for invalid casts when calling into SharedBuffer from other code.
197     if (size < 0)
198         CRASH();
199
200     append(reinterpret_cast<const char*>(data), size);
201
202 #ifdef SHARED_BUFFER_STATS
203     didCreateSharedBuffer(this);
204 #endif
205 }
206
207 SharedBuffer::~SharedBuffer()
208 {
209     clear();
210
211 #ifdef SHARED_BUFFER_STATS
212     willDestroySharedBuffer(this);
213 #endif
214 }
215
216 PassRefPtr<SharedBuffer> SharedBuffer::adoptVector(Vector<char>& vector)
217 {
218     RefPtr<SharedBuffer> buffer = create();
219     buffer->m_buffer.adopt(vector);
220     buffer->m_size = buffer->m_buffer.size();
221     return buffer.release();
222 }
223
224 unsigned SharedBuffer::size() const
225 {
226     return m_size;
227 }
228
229 const char* SharedBuffer::data() const
230 {
231     mergeSegmentsIntoBuffer();
232     return m_buffer.data();
233 }
234
235 void SharedBuffer::append(SharedBuffer* data)
236 {
237     const char* segment;
238     size_t position = 0;
239     while (size_t length = data->getSomeData(segment, position)) {
240         append(segment, length);
241         position += length;
242     }
243 }
244
245 void SharedBuffer::append(const char* data, unsigned length)
246 {
247     ASSERT(isLocked());
248     if (!length)
249         return;
250
251     ASSERT(m_size >= m_buffer.size());
252     unsigned positionInSegment = offsetInSegment(m_size - m_buffer.size());
253     m_size += length;
254
255     if (m_size <= segmentSize) {
256         // No need to use segments for small resource data.
257         m_buffer.append(data, length);
258         return;
259     }
260
261     char* segment;
262     if (!positionInSegment) {
263         segment = allocateSegment();
264         m_segments.append(segment);
265     } else
266         segment = m_segments.last() + positionInSegment;
267
268     unsigned segmentFreeSpace = segmentSize - positionInSegment;
269     unsigned bytesToCopy = min(length, segmentFreeSpace);
270
271     for (;;) {
272         memcpy(segment, data, bytesToCopy);
273         if (static_cast<unsigned>(length) == bytesToCopy)
274             break;
275
276         length -= bytesToCopy;
277         data += bytesToCopy;
278         segment = allocateSegment();
279         m_segments.append(segment);
280         bytesToCopy = min(length, segmentSize);
281     }
282 }
283
284 void SharedBuffer::append(const Vector<char>& data)
285 {
286     append(data.data(), data.size());
287 }
288
289 void SharedBuffer::clear()
290 {
291     for (unsigned i = 0; i < m_segments.size(); ++i)
292         freeSegment(m_segments[i]);
293
294     m_segments.clear();
295     m_size = 0;
296     m_buffer.clear();
297 }
298
299 PassRefPtr<SharedBuffer> SharedBuffer::copy() const
300 {
301     RefPtr<SharedBuffer> clone(adoptRef(new SharedBuffer));
302     clone->m_size = m_size;
303     clone->m_buffer.reserveCapacity(m_size);
304     clone->m_buffer.append(m_buffer.data(), m_buffer.size());
305     if (!m_segments.isEmpty()) {
306         const char* segment = 0;
307         unsigned position = m_buffer.size();
308         while (unsigned segmentSize = getSomeData(segment, position)) {
309             clone->m_buffer.append(segment, segmentSize);
310             position += segmentSize;
311         }
312         ASSERT(position == clone->size());
313     }
314     return clone.release();
315 }
316
317 void SharedBuffer::mergeSegmentsIntoBuffer() const
318 {
319     unsigned bufferSize = m_buffer.size();
320     if (m_size > bufferSize) {
321         m_buffer.reserveCapacity(m_size);
322         unsigned bytesLeft = m_size - bufferSize;
323         for (unsigned i = 0; i < m_segments.size(); ++i) {
324             unsigned bytesToCopy = min(bytesLeft, segmentSize);
325             m_buffer.append(m_segments[i], bytesToCopy);
326             bytesLeft -= bytesToCopy;
327             freeSegment(m_segments[i]);
328         }
329         m_segments.clear();
330     }
331 }
332
333 unsigned SharedBuffer::getSomeData(const char*& someData, unsigned position) const
334 {
335     ASSERT(isLocked());
336     unsigned totalSize = size();
337     if (position >= totalSize) {
338         someData = 0;
339         return 0;
340     }
341
342     ASSERT_WITH_SECURITY_IMPLICATION(position < m_size);
343     unsigned consecutiveSize = m_buffer.size();
344     if (position < consecutiveSize) {
345         someData = m_buffer.data() + position;
346         return consecutiveSize - position;
347     }
348
349     position -= consecutiveSize;
350     unsigned segments = m_segments.size();
351     unsigned maxSegmentedSize = segments * segmentSize;
352     unsigned segment = segmentIndex(position);
353     if (segment < segments) {
354         unsigned bytesLeft = totalSize - consecutiveSize;
355         unsigned segmentedSize = min(maxSegmentedSize, bytesLeft);
356
357         unsigned positionInSegment = offsetInSegment(position);
358         someData = m_segments[segment] + positionInSegment;
359         return segment == segments - 1 ? segmentedSize - position : segmentSize - positionInSegment;
360     }
361     ASSERT_NOT_REACHED();
362     return 0;
363 }
364
365 PassRefPtr<ArrayBuffer> SharedBuffer::getAsArrayBuffer() const
366 {
367     RefPtr<ArrayBuffer> arrayBuffer = ArrayBuffer::createUninitialized(static_cast<unsigned>(size()), 1);
368
369     if (!arrayBuffer)
370         return nullptr;
371
372     const char* segment = 0;
373     unsigned position = 0;
374     while (unsigned segmentSize = getSomeData(segment, position)) {
375         memcpy(static_cast<char*>(arrayBuffer->data()) + position, segment, segmentSize);
376         position += segmentSize;
377     }
378
379     if (position != arrayBuffer->byteLength()) {
380         ASSERT_NOT_REACHED();
381         // Don't return the incomplete ArrayBuffer.
382         return nullptr;
383     }
384
385     return arrayBuffer;
386 }
387
388 PassRefPtr<SkData> SharedBuffer::getAsSkData() const
389 {
390     unsigned bufferLength = size();
391     char* buffer = static_cast<char*>(sk_malloc_throw(bufferLength));
392     const char* segment = 0;
393     unsigned position = 0;
394     while (unsigned segmentSize = getSomeData(segment, position)) {
395         memcpy(buffer + position, segment, segmentSize);
396         position += segmentSize;
397     }
398
399     if (position != bufferLength) {
400         ASSERT_NOT_REACHED();
401         // Don't return the incomplete SkData.
402         return nullptr;
403     }
404     return adoptRef(SkData::NewFromMalloc(buffer, bufferLength));
405 }
406
407 bool SharedBuffer::lock()
408 {
409     return m_buffer.lock();
410 }
411
412 void SharedBuffer::unlock()
413 {
414     mergeSegmentsIntoBuffer();
415     m_buffer.unlock();
416 }
417
418 bool SharedBuffer::isLocked() const
419 {
420     return m_buffer.isLocked();
421 }
422
423 } // namespace WebCore