Home | History | Annotate | Download | only in src
      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:
     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.
     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.
    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);
    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.
    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.
    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();
    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   // A handler that is called when Log::Write fails.
    272   typedef void (*WriteFailureHandler)();
    273 
    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