OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2009 the V8 project authors. All rights reserved. | |
2 // Redistribution and use in source and binary forms, with or without | |
3 // modification, are permitted provided that the following conditions are | |
4 // met: | |
5 // | |
6 // * Redistributions of source code must retain the above copyright | |
7 // notice, this list of conditions and the following disclaimer. | |
8 // * Redistributions in binary form must reproduce the above | |
9 // copyright notice, this list of conditions and the following | |
10 // disclaimer in the documentation and/or other materials provided | |
11 // with the distribution. | |
12 // * Neither the name of Google Inc. nor the names of its | |
13 // contributors may be used to endorse or promote products derived | |
14 // from this software without specific prior written permission. | |
15 // | |
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
27 | |
28 #include "v8.h" | |
29 | |
30 #include "log-utils.h" | |
31 | |
32 namespace v8 { | |
33 namespace internal { | |
34 | |
35 #ifdef ENABLE_LOGGING_AND_PROFILING | |
36 | |
37 LogDynamicBuffer::LogDynamicBuffer(int block_size, int max_size) | |
38 : block_size_(block_size), | |
39 max_size_(max_size - (max_size % block_size_)), | |
40 blocks_(max_size_ / block_size_ + 1), | |
41 write_pos_(0), block_index_(0), block_write_pos_(0) { | |
42 ASSERT(BlocksCount() > 0); | |
43 blocks_[0] = NewArray<char>(block_size_); | |
Søren Thygesen Gjesse
2009/05/27 12:00:40
Maybe add a private method AllocateBlock.
Mikhail Naganov
2009/05/28 07:05:35
Done.
| |
44 for (int i = 1; i < BlocksCount(); ++i) { | |
45 blocks_[i] = NULL; | |
46 } | |
47 } | |
48 | |
49 | |
50 LogDynamicBuffer::~LogDynamicBuffer() { | |
51 for (int i = 0; i < BlocksCount(); ++i) { | |
52 DeleteArray(blocks_[i]); | |
53 } | |
54 } | |
55 | |
56 | |
57 int LogDynamicBuffer::Read(int from_pos, char* dest_buf, int buf_size) { | |
58 if (buf_size == 0) return 0; | |
59 int read_pos = from_pos; | |
60 int block_read_index = BlockIndex(from_pos); | |
61 int block_read_pos = PosInBlock(from_pos); | |
62 int dest_buf_pos = 0; | |
63 // Read until dest_buf is filled, or write_pos_ encountered. | |
64 while (read_pos < write_pos_ && dest_buf_pos < buf_size) { | |
65 const int read_size = Min(write_pos_ - read_pos, | |
66 Min(buf_size - dest_buf_pos, block_size_ - block_read_pos)); | |
67 memcpy(dest_buf + dest_buf_pos, | |
68 blocks_[block_read_index] + block_read_pos, read_size); | |
69 block_read_pos += read_size; | |
70 dest_buf_pos += read_size; | |
71 read_pos += read_size; | |
72 if (block_read_pos == block_size_) { | |
73 block_read_pos = 0; | |
74 ++block_read_index; | |
75 } | |
76 } | |
77 return dest_buf_pos; | |
78 } | |
79 | |
80 | |
81 int LogDynamicBuffer::Write(const char* data, int data_size) { | |
82 if ((write_pos_ + data_size) > max_size_) return 0; | |
83 int data_pos = 0; | |
84 while (data_pos < data_size) { | |
85 const int write_size = | |
86 Min(data_size - data_pos, block_size_ - block_write_pos_); | |
87 memcpy(blocks_[block_index_] + block_write_pos_, data + data_pos, | |
88 write_size); | |
89 block_write_pos_ += write_size; | |
90 data_pos += write_size; | |
91 if (block_write_pos_ == block_size_) { | |
92 block_write_pos_ = 0; | |
93 blocks_[++block_index_] = NewArray<char>(block_size_); | |
Søren Thygesen Gjesse
2009/05/27 12:00:40
Ditto.
Mikhail Naganov
2009/05/28 07:05:35
Done.
| |
94 } | |
95 } | |
96 write_pos_ += data_size; | |
97 return data_size; | |
98 } | |
99 | |
100 | |
101 Log::WritePtr Log::Write = NULL; | |
102 FILE* Log::output_handle_ = NULL; | |
103 LogDynamicBuffer* Log::output_buffer_ = NULL; | |
104 Mutex* Log::mutex_ = NULL; | |
105 char* Log::message_buffer_ = NULL; | |
106 | |
107 | |
108 void Log::Init() { | |
109 mutex_ = OS::CreateMutex(); | |
110 message_buffer_ = NewArray<char>(kMessageBufferSize); | |
111 } | |
112 | |
113 | |
114 void Log::OpenStdout() { | |
115 ASSERT(!IsEnabled()); | |
116 output_handle_ = stdout; | |
117 Write = WriteToFile; | |
118 Init(); | |
119 } | |
120 | |
121 | |
122 void Log::OpenFile(const char* name) { | |
123 ASSERT(!IsEnabled()); | |
124 output_handle_ = OS::FOpen(name, OS::LogFileOpenMode); | |
125 Write = WriteToFile; | |
126 Init(); | |
127 } | |
128 | |
129 | |
130 void Log::OpenMemoryBuffer() { | |
131 ASSERT(!IsEnabled()); | |
132 output_buffer_ = new LogDynamicBuffer( | |
133 kDynamicBufferBlockSize, kMaxDynamicBufferSize); | |
134 Write = WriteToMemory; | |
135 Init(); | |
136 } | |
137 | |
138 | |
139 void Log::Close() { | |
140 if (Write == WriteToFile) { | |
141 fclose(output_handle_); | |
142 output_handle_ = NULL; | |
143 } else if (Write == WriteToMemory) { | |
144 delete output_buffer_; | |
145 output_buffer_ = NULL; | |
146 } else { | |
147 ASSERT(Write == NULL); | |
148 } | |
149 Write = NULL; | |
150 | |
151 delete mutex_; | |
152 mutex_ = NULL; | |
153 } | |
154 | |
155 | |
156 int Log::GetLogLines(int from_pos, char* dest_buf, int max_size) { | |
157 if (Write != WriteToMemory) return 0; | |
158 ASSERT(output_buffer_ != NULL); | |
159 ASSERT(from_pos >= 0); | |
160 ASSERT(max_size >= 0); | |
161 int actual_size = output_buffer_->Read(from_pos, dest_buf, max_size); | |
162 ASSERT(actual_size <= max_size); | |
163 if (actual_size == 0) return 0; | |
164 | |
165 // Find previous log line boundary. | |
166 char* end_pos = dest_buf + actual_size - 1; | |
167 while (end_pos >= dest_buf && *end_pos != '\n') --end_pos; | |
168 actual_size = end_pos - dest_buf + 1; | |
169 ASSERT(actual_size <= max_size); | |
170 return actual_size; | |
171 } | |
172 | |
173 | |
174 LogMessageBuilder::LogMessageBuilder(): sl(Log::mutex_), pos_(0) { | |
175 ASSERT(Log::message_buffer_ != NULL); | |
176 } | |
177 | |
178 | |
179 void LogMessageBuilder::Append(const char* format, ...) { | |
180 Vector<char> buf(Log::message_buffer_ + pos_, | |
181 Log::kMessageBufferSize - pos_); | |
182 va_list args; | |
183 va_start(args, format); | |
184 Append(format, args); | |
185 va_end(args); | |
186 ASSERT(pos_ <= Log::kMessageBufferSize); | |
187 } | |
188 | |
189 | |
190 void LogMessageBuilder::Append(const char* format, va_list args) { | |
191 Vector<char> buf(Log::message_buffer_ + pos_, | |
192 Log::kMessageBufferSize - pos_); | |
193 int result = v8::internal::OS::VSNPrintF(buf, format, args); | |
194 | |
195 // Result is -1 if output was truncated. | |
196 if (result >= 0) { | |
197 pos_ += result; | |
198 } else { | |
199 pos_ = Log::kMessageBufferSize; | |
200 } | |
201 ASSERT(pos_ <= Log::kMessageBufferSize); | |
202 } | |
203 | |
204 | |
205 void LogMessageBuilder::Append(const char c) { | |
206 if (pos_ < Log::kMessageBufferSize) { | |
207 Log::message_buffer_[pos_++] = c; | |
208 } | |
209 ASSERT(pos_ <= Log::kMessageBufferSize); | |
210 } | |
211 | |
212 | |
213 void LogMessageBuilder::Append(String* str) { | |
214 AssertNoAllocation no_heap_allocation; // Ensure string stay valid. | |
215 int length = str->length(); | |
216 for (int i = 0; i < length; i++) { | |
217 Append(static_cast<char>(str->Get(i))); | |
218 } | |
219 } | |
220 | |
221 | |
222 void LogMessageBuilder::AppendDetailed(String* str, bool show_impl_info) { | |
223 AssertNoAllocation no_heap_allocation; // Ensure string stay valid. | |
224 int len = str->length(); | |
225 if (len > 0x1000) | |
226 len = 0x1000; | |
227 if (show_impl_info) { | |
228 Append(str->IsAsciiRepresentation() ? 'a' : '2'); | |
229 if (StringShape(str).IsExternal()) | |
230 Append('e'); | |
231 if (StringShape(str).IsSymbol()) | |
232 Append('#'); | |
233 Append(":%i:", str->length()); | |
234 } | |
235 for (int i = 0; i < len; i++) { | |
236 uc32 c = str->Get(i); | |
237 if (c > 0xff) { | |
238 Append("\\u%04x", c); | |
239 } else if (c < 32 || c > 126) { | |
240 Append("\\x%02x", c); | |
241 } else if (c == ',') { | |
242 Append("\\,"); | |
243 } else if (c == '\\') { | |
244 Append("\\\\"); | |
245 } else { | |
246 Append("%lc", c); | |
247 } | |
248 } | |
249 } | |
250 | |
251 | |
252 void LogMessageBuilder::WriteToLogFile() { | |
253 ASSERT(pos_ <= Log::kMessageBufferSize); | |
254 Log::Write(Log::message_buffer_, pos_); | |
255 } | |
256 | |
257 | |
258 void LogMessageBuilder::WriteCStringToLogFile(const char* str) { | |
259 int len = strlen(str); | |
260 Log::Write(str, len); | |
261 } | |
262 | |
263 #endif // ENABLE_LOGGING_AND_PROFILING | |
264 | |
265 } } // namespace v8::internal | |
OLD | NEW |