Chromium Code Reviews| Index: src/log-utils.cc |
| diff --git a/src/log-utils.cc b/src/log-utils.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..0ccd4f2d6efcc0c552b0d05420c801836f9891c6 |
| --- /dev/null |
| +++ b/src/log-utils.cc |
| @@ -0,0 +1,265 @@ |
| +// Copyright 2009 the V8 project authors. All rights reserved. |
| +// Redistribution and use in source and binary forms, with or without |
| +// modification, are permitted provided that the following conditions are |
| +// met: |
| +// |
| +// * Redistributions of source code must retain the above copyright |
| +// notice, this list of conditions and the following disclaimer. |
| +// * Redistributions in binary form must reproduce the above |
| +// copyright notice, this list of conditions and the following |
| +// disclaimer in the documentation and/or other materials provided |
| +// with the distribution. |
| +// * Neither the name of Google Inc. nor the names of its |
| +// contributors may be used to endorse or promote products derived |
| +// from this software without specific prior written permission. |
| +// |
| +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| + |
| +#include "v8.h" |
| + |
| +#include "log-utils.h" |
| + |
| +namespace v8 { |
| +namespace internal { |
| + |
| +#ifdef ENABLE_LOGGING_AND_PROFILING |
| + |
| +LogDynamicBuffer::LogDynamicBuffer(int block_size, int max_size) |
| + : block_size_(block_size), |
| + max_size_(max_size - (max_size % block_size_)), |
| + blocks_(max_size_ / block_size_ + 1), |
| + write_pos_(0), block_index_(0), block_write_pos_(0) { |
| + ASSERT(BlocksCount() > 0); |
| + 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.
|
| + for (int i = 1; i < BlocksCount(); ++i) { |
| + blocks_[i] = NULL; |
| + } |
| +} |
| + |
| + |
| +LogDynamicBuffer::~LogDynamicBuffer() { |
| + for (int i = 0; i < BlocksCount(); ++i) { |
| + DeleteArray(blocks_[i]); |
| + } |
| +} |
| + |
| + |
| +int LogDynamicBuffer::Read(int from_pos, char* dest_buf, int buf_size) { |
| + if (buf_size == 0) return 0; |
| + int read_pos = from_pos; |
| + int block_read_index = BlockIndex(from_pos); |
| + int block_read_pos = PosInBlock(from_pos); |
| + int dest_buf_pos = 0; |
| + // Read until dest_buf is filled, or write_pos_ encountered. |
| + while (read_pos < write_pos_ && dest_buf_pos < buf_size) { |
| + const int read_size = Min(write_pos_ - read_pos, |
| + Min(buf_size - dest_buf_pos, block_size_ - block_read_pos)); |
| + memcpy(dest_buf + dest_buf_pos, |
| + blocks_[block_read_index] + block_read_pos, read_size); |
| + block_read_pos += read_size; |
| + dest_buf_pos += read_size; |
| + read_pos += read_size; |
| + if (block_read_pos == block_size_) { |
| + block_read_pos = 0; |
| + ++block_read_index; |
| + } |
| + } |
| + return dest_buf_pos; |
| +} |
| + |
| + |
| +int LogDynamicBuffer::Write(const char* data, int data_size) { |
| + if ((write_pos_ + data_size) > max_size_) return 0; |
| + int data_pos = 0; |
| + while (data_pos < data_size) { |
| + const int write_size = |
| + Min(data_size - data_pos, block_size_ - block_write_pos_); |
| + memcpy(blocks_[block_index_] + block_write_pos_, data + data_pos, |
| + write_size); |
| + block_write_pos_ += write_size; |
| + data_pos += write_size; |
| + if (block_write_pos_ == block_size_) { |
| + block_write_pos_ = 0; |
| + 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.
|
| + } |
| + } |
| + write_pos_ += data_size; |
| + return data_size; |
| +} |
| + |
| + |
| +Log::WritePtr Log::Write = NULL; |
| +FILE* Log::output_handle_ = NULL; |
| +LogDynamicBuffer* Log::output_buffer_ = NULL; |
| +Mutex* Log::mutex_ = NULL; |
| +char* Log::message_buffer_ = NULL; |
| + |
| + |
| +void Log::Init() { |
| + mutex_ = OS::CreateMutex(); |
| + message_buffer_ = NewArray<char>(kMessageBufferSize); |
| +} |
| + |
| + |
| +void Log::OpenStdout() { |
| + ASSERT(!IsEnabled()); |
| + output_handle_ = stdout; |
| + Write = WriteToFile; |
| + Init(); |
| +} |
| + |
| + |
| +void Log::OpenFile(const char* name) { |
| + ASSERT(!IsEnabled()); |
| + output_handle_ = OS::FOpen(name, OS::LogFileOpenMode); |
| + Write = WriteToFile; |
| + Init(); |
| +} |
| + |
| + |
| +void Log::OpenMemoryBuffer() { |
| + ASSERT(!IsEnabled()); |
| + output_buffer_ = new LogDynamicBuffer( |
| + kDynamicBufferBlockSize, kMaxDynamicBufferSize); |
| + Write = WriteToMemory; |
| + Init(); |
| +} |
| + |
| + |
| +void Log::Close() { |
| + if (Write == WriteToFile) { |
| + fclose(output_handle_); |
| + output_handle_ = NULL; |
| + } else if (Write == WriteToMemory) { |
| + delete output_buffer_; |
| + output_buffer_ = NULL; |
| + } else { |
| + ASSERT(Write == NULL); |
| + } |
| + Write = NULL; |
| + |
| + delete mutex_; |
| + mutex_ = NULL; |
| +} |
| + |
| + |
| +int Log::GetLogLines(int from_pos, char* dest_buf, int max_size) { |
| + if (Write != WriteToMemory) return 0; |
| + ASSERT(output_buffer_ != NULL); |
| + ASSERT(from_pos >= 0); |
| + ASSERT(max_size >= 0); |
| + int actual_size = output_buffer_->Read(from_pos, dest_buf, max_size); |
| + ASSERT(actual_size <= max_size); |
| + if (actual_size == 0) return 0; |
| + |
| + // Find previous log line boundary. |
| + char* end_pos = dest_buf + actual_size - 1; |
| + while (end_pos >= dest_buf && *end_pos != '\n') --end_pos; |
| + actual_size = end_pos - dest_buf + 1; |
| + ASSERT(actual_size <= max_size); |
| + return actual_size; |
| +} |
| + |
| + |
| +LogMessageBuilder::LogMessageBuilder(): sl(Log::mutex_), pos_(0) { |
| + ASSERT(Log::message_buffer_ != NULL); |
| +} |
| + |
| + |
| +void LogMessageBuilder::Append(const char* format, ...) { |
| + Vector<char> buf(Log::message_buffer_ + pos_, |
| + Log::kMessageBufferSize - pos_); |
| + va_list args; |
| + va_start(args, format); |
| + Append(format, args); |
| + va_end(args); |
| + ASSERT(pos_ <= Log::kMessageBufferSize); |
| +} |
| + |
| + |
| +void LogMessageBuilder::Append(const char* format, va_list args) { |
| + Vector<char> buf(Log::message_buffer_ + pos_, |
| + Log::kMessageBufferSize - pos_); |
| + int result = v8::internal::OS::VSNPrintF(buf, format, args); |
| + |
| + // Result is -1 if output was truncated. |
| + if (result >= 0) { |
| + pos_ += result; |
| + } else { |
| + pos_ = Log::kMessageBufferSize; |
| + } |
| + ASSERT(pos_ <= Log::kMessageBufferSize); |
| +} |
| + |
| + |
| +void LogMessageBuilder::Append(const char c) { |
| + if (pos_ < Log::kMessageBufferSize) { |
| + Log::message_buffer_[pos_++] = c; |
| + } |
| + ASSERT(pos_ <= Log::kMessageBufferSize); |
| +} |
| + |
| + |
| +void LogMessageBuilder::Append(String* str) { |
| + AssertNoAllocation no_heap_allocation; // Ensure string stay valid. |
| + int length = str->length(); |
| + for (int i = 0; i < length; i++) { |
| + Append(static_cast<char>(str->Get(i))); |
| + } |
| +} |
| + |
| + |
| +void LogMessageBuilder::AppendDetailed(String* str, bool show_impl_info) { |
| + AssertNoAllocation no_heap_allocation; // Ensure string stay valid. |
| + int len = str->length(); |
| + if (len > 0x1000) |
| + len = 0x1000; |
| + if (show_impl_info) { |
| + Append(str->IsAsciiRepresentation() ? 'a' : '2'); |
| + if (StringShape(str).IsExternal()) |
| + Append('e'); |
| + if (StringShape(str).IsSymbol()) |
| + Append('#'); |
| + Append(":%i:", str->length()); |
| + } |
| + for (int i = 0; i < len; i++) { |
| + uc32 c = str->Get(i); |
| + if (c > 0xff) { |
| + Append("\\u%04x", c); |
| + } else if (c < 32 || c > 126) { |
| + Append("\\x%02x", c); |
| + } else if (c == ',') { |
| + Append("\\,"); |
| + } else if (c == '\\') { |
| + Append("\\\\"); |
| + } else { |
| + Append("%lc", c); |
| + } |
| + } |
| +} |
| + |
| + |
| +void LogMessageBuilder::WriteToLogFile() { |
| + ASSERT(pos_ <= Log::kMessageBufferSize); |
| + Log::Write(Log::message_buffer_, pos_); |
| +} |
| + |
| + |
| +void LogMessageBuilder::WriteCStringToLogFile(const char* str) { |
| + int len = strlen(str); |
| + Log::Write(str, len); |
| +} |
| + |
| +#endif // ENABLE_LOGGING_AND_PROFILING |
| + |
| +} } // namespace v8::internal |