• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // 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 
31 namespace v8 {
32 namespace 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.
45 class 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:
AllocateBlock(int index)65   void AllocateBlock(int index) {
66     blocks_[index] = NewArray<char>(block_size_);
67   }
68 
BlockIndex(int pos)69   int BlockIndex(int pos) const { return pos / block_size_; }
70 
BlocksCount()71   int BlocksCount() const { return BlockIndex(max_size_) + 1; }
72 
PosInBlock(int pos)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.
92 class 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.
stop()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.
IsEnabled()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.
WriteToFile(const char * msg,int length)130   static int WriteToFile(const char* msg, int length) {
131     ASSERT(output_handle_ != NULL);
132     size_t rv = fwrite(msg, 1, length, output_handle_);
133     ASSERT(static_cast<size_t>(length) == rv);
134     USE(rv);
135     return length;
136   }
137 
138   // Implementation of writing to a memory buffer.
WriteToMemory(const char * msg,int length)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.
180 class LogRecordCompressor {
181  public:
182   // 'window_size' is the size of backward lookup window.
LogRecordCompressor(int window_size)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.
223 class 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();
~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.
RetrieveCompressedPrevious(LogRecordCompressor * compressor)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   // A handler that is called when Log::Write fails.
272   typedef void (*WriteFailureHandler)();
273 
set_write_failure_handler(WriteFailureHandler handler)274   static void set_write_failure_handler(WriteFailureHandler handler) {
275     write_failure_handler = handler;
276   }
277 
278  private:
279   static WriteFailureHandler write_failure_handler;
280 
281   ScopedLock sl;
282   int pos_;
283 };
284 
285 #endif  // ENABLE_LOGGING_AND_PROFILING
286 
287 } }  // namespace v8::internal
288 
289 #endif  // V8_LOG_UTILS_H_
290