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