blob: 3e25b0e75744fd13a978d053baff14a9de3e308d [file] [log] [blame]
Steve Blocka7e24c12009-10-30 11:49:00 +00001// Copyright 2006-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#ifndef V8_LOG_UTILS_H_
29#define V8_LOG_UTILS_H_
30
31namespace v8 {
32namespace internal {
33
34#ifdef ENABLE_LOGGING_AND_PROFILING
35
36// A memory buffer that increments its size as you write in it. Size
37// is incremented with 'block_size' steps, never exceeding 'max_size'.
38// During growth, memory contents are never copied. At the end of the
39// buffer an amount of memory specified in 'seal_size' is reserved.
40// When writing position reaches max_size - seal_size, buffer auto-seals
41// itself with 'seal' and allows no further writes. Data pointed by
42// 'seal' must be available during entire LogDynamicBuffer lifetime.
43//
44// An instance of this class is created dynamically by Log.
45class LogDynamicBuffer {
46 public:
47 LogDynamicBuffer(
48 int block_size, int max_size, const char* seal, int seal_size);
49
50 ~LogDynamicBuffer();
51
52 // Reads contents of the buffer starting from 'from_pos'. Upon
53 // return, 'dest_buf' is filled with the data. Actual amount of data
54 // filled is returned, it is <= 'buf_size'.
55 int Read(int from_pos, char* dest_buf, int buf_size);
56
57 // Writes 'data' to the buffer, making it larger if necessary. If
58 // data is too big to fit in the buffer, it doesn't get written at
59 // all. In that case, buffer auto-seals itself and stops to accept
60 // any incoming writes. Returns amount of data written (it is either
61 // 'data_size', or 0, if 'data' is too big).
62 int Write(const char* data, int data_size);
63
64 private:
65 void AllocateBlock(int index) {
66 blocks_[index] = NewArray<char>(block_size_);
67 }
68
69 int BlockIndex(int pos) const { return pos / block_size_; }
70
71 int BlocksCount() const { return BlockIndex(max_size_) + 1; }
72
73 int PosInBlock(int pos) const { return pos % block_size_; }
74
75 int Seal();
76
77 int WriteInternal(const char* data, int data_size);
78
79 const int block_size_;
80 const int max_size_;
81 const char* seal_;
82 const int seal_size_;
83 ScopedVector<char*> blocks_;
84 int write_pos_;
85 int block_index_;
86 int block_write_pos_;
87 bool is_sealed_;
88};
89
90
91// Functions and data for performing output of log messages.
92class Log : public AllStatic {
93 public:
94 // Opens stdout for logging.
95 static void OpenStdout();
96
97 // Opens file for logging.
98 static void OpenFile(const char* name);
99
100 // Opens memory buffer for logging.
101 static void OpenMemoryBuffer();
102
103 // Disables logging, but preserves acquired resources.
104 static void stop() { is_stopped_ = true; }
105
106 // Frees all resources acquired in Open... functions.
107 static void Close();
108
109 // See description in include/v8.h.
110 static int GetLogLines(int from_pos, char* dest_buf, int max_size);
111
112 // Returns whether logging is enabled.
113 static bool IsEnabled() {
114 return !is_stopped_ && (output_handle_ != NULL || output_buffer_ != NULL);
115 }
116
117 // Size of buffer used for formatting log messages.
118 static const int kMessageBufferSize = 2048;
119
120 private:
121 typedef int (*WritePtr)(const char* msg, int length);
122
123 // Initialization function called from Open... functions.
124 static void Init();
125
126 // Write functions assume that mutex_ is acquired by the caller.
127 static WritePtr Write;
128
129 // Implementation of writing to a log file.
130 static int WriteToFile(const char* msg, int length) {
131 ASSERT(output_handle_ != NULL);
Steve Blockd0582a62009-12-15 09:54:21 +0000132 size_t rv = fwrite(msg, 1, length, output_handle_);
133 ASSERT(static_cast<size_t>(length) == rv);
134 USE(rv);
135 return length;
Steve Blocka7e24c12009-10-30 11:49:00 +0000136 }
137
138 // Implementation of writing to a memory buffer.
139 static int WriteToMemory(const char* msg, int length) {
140 ASSERT(output_buffer_ != NULL);
141 return output_buffer_->Write(msg, length);
142 }
143
144 // Whether logging is stopped (e.g. due to insufficient resources).
145 static bool is_stopped_;
146
147 // When logging is active, either output_handle_ or output_buffer_ is used
148 // to store a pointer to log destination. If logging was opened via OpenStdout
149 // or OpenFile, then output_handle_ is used. If logging was opened
150 // via OpenMemoryBuffer, then output_buffer_ is used.
151 // mutex_ should be acquired before using output_handle_ or output_buffer_.
152 static FILE* output_handle_;
153
154 static LogDynamicBuffer* output_buffer_;
155
156 // Size of dynamic buffer block (and dynamic buffer initial size).
157 static const int kDynamicBufferBlockSize = 65536;
158
159 // Maximum size of dynamic buffer.
160 static const int kMaxDynamicBufferSize = 50 * 1024 * 1024;
161
162 // Message to "seal" dynamic buffer with.
163 static const char* kDynamicBufferSeal;
164
165 // mutex_ is a Mutex used for enforcing exclusive
166 // access to the formatting buffer and the log file or log memory buffer.
167 static Mutex* mutex_;
168
169 // Buffer used for formatting log messages. This is a singleton buffer and
170 // mutex_ should be acquired before using it.
171 static char* message_buffer_;
172
173 friend class LogMessageBuilder;
174 friend class LogRecordCompressor;
175};
176
177
178// An utility class for performing backward reference compression
179// of string ends. It operates using a window of previous strings.
180class LogRecordCompressor {
181 public:
182 // 'window_size' is the size of backward lookup window.
183 explicit LogRecordCompressor(int window_size)
184 : buffer_(window_size + kNoCompressionWindowSize),
185 kMaxBackwardReferenceSize(
186 GetBackwardReferenceSize(window_size, Log::kMessageBufferSize)),
187 curr_(-1), prev_(-1) {
188 }
189
190 ~LogRecordCompressor();
191
192 // Fills vector with a compressed version of the previous record.
193 // Returns false if there is no previous record.
194 bool RetrievePreviousCompressed(Vector<char>* prev_record);
195
196 // Stores a record if it differs from a previous one (or there's no previous).
197 // Returns true, if the record has been stored.
198 bool Store(const Vector<const char>& record);
199
200 private:
201 // The minimum size of a buffer: a place needed for the current and
202 // the previous record. Since there is no place for precedessors of a previous
203 // record, it can't be compressed at all.
204 static const int kNoCompressionWindowSize = 2;
205
206 // Formatting strings for back references.
207 static const char* kLineBackwardReferenceFormat;
208 static const char* kBackwardReferenceFormat;
209
210 static int GetBackwardReferenceSize(int distance, int pos);
211
212 static void PrintBackwardReference(Vector<char> dest, int distance, int pos);
213
214 ScopedVector< Vector<const char> > buffer_;
215 const int kMaxBackwardReferenceSize;
216 int curr_;
217 int prev_;
218};
219
220
221// Utility class for formatting log messages. It fills the message into the
222// static buffer in Log.
223class LogMessageBuilder BASE_EMBEDDED {
224 public:
225 // Create a message builder starting from position 0. This acquires the mutex
226 // in the log as well.
227 explicit LogMessageBuilder();
228 ~LogMessageBuilder() { }
229
230 // Append string data to the log message.
231 void Append(const char* format, ...);
232
233 // Append string data to the log message.
234 void AppendVA(const char* format, va_list args);
235
236 // Append a character to the log message.
237 void Append(const char c);
238
239 // Append a heap string.
240 void Append(String* str);
241
242 // Appends an address, compressing it if needed by offsetting
243 // from Logger::last_address_.
244 void AppendAddress(Address addr);
245
246 // Appends an address, compressing it if needed.
247 void AppendAddress(Address addr, Address bias);
248
249 void AppendDetailed(String* str, bool show_impl_info);
250
251 // Append a portion of a string.
252 void AppendStringPart(const char* str, int len);
253
254 // Stores log message into compressor, returns true if the message
255 // was stored (i.e. doesn't repeat the previous one).
256 bool StoreInCompressor(LogRecordCompressor* compressor);
257
258 // Sets log message to a previous version of compressed message.
259 // Returns false, if there is no previous message.
260 bool RetrieveCompressedPrevious(LogRecordCompressor* compressor) {
261 return RetrieveCompressedPrevious(compressor, "");
262 }
263
264 // Does the same at the version without arguments, and sets a prefix.
265 bool RetrieveCompressedPrevious(LogRecordCompressor* compressor,
266 const char* prefix);
267
268 // Write the log message to the log file currently opened.
269 void WriteToLogFile();
270
271 // Write a null-terminated string to to the log file currently opened.
272 void WriteCStringToLogFile(const char* str);
273
274 // A handler that is called when Log::Write fails.
275 typedef void (*WriteFailureHandler)();
276
277 static void set_write_failure_handler(WriteFailureHandler handler) {
278 write_failure_handler = handler;
279 }
280
281 private:
282 static WriteFailureHandler write_failure_handler;
283
284 ScopedLock sl;
285 int pos_;
286};
287
288#endif // ENABLE_LOGGING_AND_PROFILING
289
290} } // namespace v8::internal
291
292#endif // V8_LOG_UTILS_H_