Upstream version 5.34.92.0
[platform/framework/web/crosswalk.git] / src / mojo / public / bindings / lib / buffer.cc
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "mojo/public/bindings/lib/buffer.h"
6
7 #include <assert.h>
8 #include <stdlib.h>
9 #include <string.h>
10
11 #include <algorithm>
12
13 #include "mojo/public/bindings/lib/bindings_serialization.h"
14 #include "mojo/public/environment/buffer_tls.h"
15
16 // Scrub memory in debug builds to help catch use-after-free bugs.
17 #ifdef NDEBUG
18 #define DEBUG_SCRUB(address, size) (void) (address), (void) (size)
19 #else
20 #define DEBUG_SCRUB(address, size) memset(address, 0xCD, size)
21 #endif
22
23 namespace mojo {
24
25 //-----------------------------------------------------------------------------
26
27 Buffer::Buffer() {
28   previous_ = internal::SetCurrentBuffer(this);
29 }
30
31 Buffer::~Buffer() {
32   Buffer* buf MOJO_ALLOW_UNUSED = internal::SetCurrentBuffer(previous_);
33   assert(buf == this);
34 }
35
36 Buffer* Buffer::current() {
37   return internal::GetCurrentBuffer();
38 }
39
40 //-----------------------------------------------------------------------------
41
42 namespace internal {
43
44 ScratchBuffer::ScratchBuffer()
45     : overflow_(NULL) {
46   fixed_.next = NULL;
47   fixed_.cursor = fixed_data_;
48   fixed_.end = fixed_data_ + kMinSegmentSize;
49 }
50
51 ScratchBuffer::~ScratchBuffer() {
52   // Invoke destructors in reverse order to mirror allocation order.
53   std::deque<PendingDestructor>::reverse_iterator it;
54   for (it = pending_dtors_.rbegin(); it != pending_dtors_.rend(); ++it)
55     it->func(it->address);
56
57   while (overflow_) {
58     Segment* doomed = overflow_;
59     overflow_ = overflow_->next;
60     DEBUG_SCRUB(doomed, doomed->end - reinterpret_cast<char*>(doomed));
61     free(doomed);
62   }
63   DEBUG_SCRUB(fixed_data_, sizeof(fixed_data_));
64 }
65
66 void* ScratchBuffer::Allocate(size_t delta, Destructor func) {
67   delta = internal::Align(delta);
68
69   void* result = AllocateInSegment(&fixed_, delta);
70   if (!result) {
71     if (overflow_)
72       result = AllocateInSegment(overflow_, delta);
73
74     if (!result) {
75       AddOverflowSegment(delta);
76       result = AllocateInSegment(overflow_, delta);
77     }
78   }
79
80   if (func) {
81     PendingDestructor dtor;
82     dtor.func = func;
83     dtor.address = result;
84     pending_dtors_.push_back(dtor);
85   }
86   return result;
87 }
88
89 void* ScratchBuffer::AllocateInSegment(Segment* segment, size_t delta) {
90   void* result;
91   if (static_cast<size_t>(segment->end - segment->cursor) >= delta) {
92     result = segment->cursor;
93     memset(result, 0, delta);
94     segment->cursor += delta;
95   } else {
96     result = NULL;
97   }
98   return result;
99 }
100
101 void ScratchBuffer::AddOverflowSegment(size_t delta) {
102   if (delta < kMinSegmentSize)
103     delta = kMinSegmentSize;
104
105   // Ensure segment buffer is aligned.
106   size_t segment_size = internal::Align(sizeof(Segment)) + delta;
107
108   Segment* segment = static_cast<Segment*>(malloc(segment_size));
109   segment->next = overflow_;
110   segment->cursor = reinterpret_cast<char*>(segment + 1);
111   segment->end = segment->cursor + delta;
112
113   overflow_ = segment;
114 }
115
116 //-----------------------------------------------------------------------------
117
118 FixedBuffer::FixedBuffer(size_t size)
119     : ptr_(NULL),
120       cursor_(0),
121       size_(internal::Align(size)) {
122   ptr_ = static_cast<char*>(calloc(size_, 1));
123 }
124
125 FixedBuffer::~FixedBuffer() {
126   free(ptr_);
127 }
128
129 void* FixedBuffer::Allocate(size_t delta, Destructor dtor) {
130   assert(!dtor);
131
132   delta = internal::Align(delta);
133
134   // TODO(darin): Using <assert.h> is probably not going to cut it.
135   assert(delta > 0);
136   assert(cursor_ + delta <= size_);
137   if (cursor_ + delta > size_)
138     return NULL;
139
140   char* result = ptr_ + cursor_;
141   cursor_ += delta;
142
143   return result;
144 }
145
146 void* FixedBuffer::Leak() {
147   char* ptr = ptr_;
148   ptr_ = NULL;
149   cursor_ = 0;
150   size_ = 0;
151   return ptr;
152 }
153
154 }  // namespace internal
155 }  // namespace mojo