Home | History | Annotate | Download | only in src
      1 // Copyright 2009 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "src/v8.h"
      6 
      7 #include "src/log-utils.h"
      8 #include "src/string-stream.h"
      9 
     10 namespace v8 {
     11 namespace internal {
     12 
     13 
     14 const char* const Log::kLogToTemporaryFile = "&";
     15 const char* const Log::kLogToConsole = "-";
     16 
     17 
     18 Log::Log(Logger* logger)
     19   : is_stopped_(false),
     20     output_handle_(NULL),
     21     message_buffer_(NULL),
     22     logger_(logger) {
     23 }
     24 
     25 
     26 void Log::Initialize(const char* log_file_name) {
     27   message_buffer_ = NewArray<char>(kMessageBufferSize);
     28 
     29   // --log-all enables all the log flags.
     30   if (FLAG_log_all) {
     31     FLAG_log_api = true;
     32     FLAG_log_code = true;
     33     FLAG_log_gc = true;
     34     FLAG_log_suspect = true;
     35     FLAG_log_handles = true;
     36     FLAG_log_regexp = true;
     37     FLAG_log_internal_timer_events = true;
     38   }
     39 
     40   // --prof implies --log-code.
     41   if (FLAG_prof) FLAG_log_code = true;
     42 
     43   // If we're logging anything, we need to open the log file.
     44   if (Log::InitLogAtStart()) {
     45     if (strcmp(log_file_name, kLogToConsole) == 0) {
     46       OpenStdout();
     47     } else if (strcmp(log_file_name, kLogToTemporaryFile) == 0) {
     48       OpenTemporaryFile();
     49     } else {
     50       OpenFile(log_file_name);
     51     }
     52   }
     53 }
     54 
     55 
     56 void Log::OpenStdout() {
     57   ASSERT(!IsEnabled());
     58   output_handle_ = stdout;
     59 }
     60 
     61 
     62 void Log::OpenTemporaryFile() {
     63   ASSERT(!IsEnabled());
     64   output_handle_ = i::OS::OpenTemporaryFile();
     65 }
     66 
     67 
     68 void Log::OpenFile(const char* name) {
     69   ASSERT(!IsEnabled());
     70   output_handle_ = OS::FOpen(name, OS::LogFileOpenMode);
     71 }
     72 
     73 
     74 FILE* Log::Close() {
     75   FILE* result = NULL;
     76   if (output_handle_ != NULL) {
     77     if (strcmp(FLAG_logfile, kLogToTemporaryFile) != 0) {
     78       fclose(output_handle_);
     79     } else {
     80       result = output_handle_;
     81     }
     82   }
     83   output_handle_ = NULL;
     84 
     85   DeleteArray(message_buffer_);
     86   message_buffer_ = NULL;
     87 
     88   is_stopped_ = false;
     89   return result;
     90 }
     91 
     92 
     93 Log::MessageBuilder::MessageBuilder(Log* log)
     94   : log_(log),
     95     lock_guard_(&log_->mutex_),
     96     pos_(0) {
     97   ASSERT(log_->message_buffer_ != NULL);
     98 }
     99 
    100 
    101 void Log::MessageBuilder::Append(const char* format, ...) {
    102   Vector<char> buf(log_->message_buffer_ + pos_,
    103                    Log::kMessageBufferSize - pos_);
    104   va_list args;
    105   va_start(args, format);
    106   AppendVA(format, args);
    107   va_end(args);
    108   ASSERT(pos_ <= Log::kMessageBufferSize);
    109 }
    110 
    111 
    112 void Log::MessageBuilder::AppendVA(const char* format, va_list args) {
    113   Vector<char> buf(log_->message_buffer_ + pos_,
    114                    Log::kMessageBufferSize - pos_);
    115   int result = v8::internal::VSNPrintF(buf, format, args);
    116 
    117   // Result is -1 if output was truncated.
    118   if (result >= 0) {
    119     pos_ += result;
    120   } else {
    121     pos_ = Log::kMessageBufferSize;
    122   }
    123   ASSERT(pos_ <= Log::kMessageBufferSize);
    124 }
    125 
    126 
    127 void Log::MessageBuilder::Append(const char c) {
    128   if (pos_ < Log::kMessageBufferSize) {
    129     log_->message_buffer_[pos_++] = c;
    130   }
    131   ASSERT(pos_ <= Log::kMessageBufferSize);
    132 }
    133 
    134 
    135 void Log::MessageBuilder::AppendDoubleQuotedString(const char* string) {
    136   Append('"');
    137   for (const char* p = string; *p != '\0'; p++) {
    138     if (*p == '"') {
    139       Append('\\');
    140     }
    141     Append(*p);
    142   }
    143   Append('"');
    144 }
    145 
    146 
    147 void Log::MessageBuilder::Append(String* str) {
    148   DisallowHeapAllocation no_gc;  // Ensure string stay valid.
    149   int length = str->length();
    150   for (int i = 0; i < length; i++) {
    151     Append(static_cast<char>(str->Get(i)));
    152   }
    153 }
    154 
    155 
    156 void Log::MessageBuilder::AppendAddress(Address addr) {
    157   Append("0x%" V8PRIxPTR, addr);
    158 }
    159 
    160 
    161 void Log::MessageBuilder::AppendSymbolName(Symbol* symbol) {
    162   ASSERT(symbol);
    163   Append("symbol(");
    164   if (!symbol->name()->IsUndefined()) {
    165     Append("\"");
    166     AppendDetailed(String::cast(symbol->name()), false);
    167     Append("\" ");
    168   }
    169   Append("hash %x)", symbol->Hash());
    170 }
    171 
    172 
    173 void Log::MessageBuilder::AppendDetailed(String* str, bool show_impl_info) {
    174   if (str == NULL) return;
    175   DisallowHeapAllocation no_gc;  // Ensure string stay valid.
    176   int len = str->length();
    177   if (len > 0x1000)
    178     len = 0x1000;
    179   if (show_impl_info) {
    180     Append(str->IsOneByteRepresentation() ? 'a' : '2');
    181     if (StringShape(str).IsExternal())
    182       Append('e');
    183     if (StringShape(str).IsInternalized())
    184       Append('#');
    185     Append(":%i:", str->length());
    186   }
    187   for (int i = 0; i < len; i++) {
    188     uc32 c = str->Get(i);
    189     if (c > 0xff) {
    190       Append("\\u%04x", c);
    191     } else if (c < 32 || c > 126) {
    192       Append("\\x%02x", c);
    193     } else if (c == ',') {
    194       Append("\\,");
    195     } else if (c == '\\') {
    196       Append("\\\\");
    197     } else if (c == '\"') {
    198       Append("\"\"");
    199     } else {
    200       Append("%lc", c);
    201     }
    202   }
    203 }
    204 
    205 
    206 void Log::MessageBuilder::AppendStringPart(const char* str, int len) {
    207   if (pos_ + len > Log::kMessageBufferSize) {
    208     len = Log::kMessageBufferSize - pos_;
    209     ASSERT(len >= 0);
    210     if (len == 0) return;
    211   }
    212   Vector<char> buf(log_->message_buffer_ + pos_,
    213                    Log::kMessageBufferSize - pos_);
    214   StrNCpy(buf, str, len);
    215   pos_ += len;
    216   ASSERT(pos_ <= Log::kMessageBufferSize);
    217 }
    218 
    219 
    220 void Log::MessageBuilder::WriteToLogFile() {
    221   ASSERT(pos_ <= Log::kMessageBufferSize);
    222   const int written = log_->WriteToFile(log_->message_buffer_, pos_);
    223   if (written != pos_) {
    224     log_->stop();
    225     log_->logger_->LogFailure();
    226   }
    227 }
    228 
    229 
    230 } }  // namespace v8::internal
    231