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 DCHECK(!IsEnabled()); 58 output_handle_ = stdout; 59 } 60 61 62 void Log::OpenTemporaryFile() { 63 DCHECK(!IsEnabled()); 64 output_handle_ = base::OS::OpenTemporaryFile(); 65 } 66 67 68 void Log::OpenFile(const char* name) { 69 DCHECK(!IsEnabled()); 70 output_handle_ = base::OS::FOpen(name, base::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 DCHECK(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 DCHECK(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 DCHECK(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 DCHECK(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 DCHECK(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 DCHECK(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 DCHECK(pos_ <= Log::kMessageBufferSize); 217 } 218 219 220 void Log::MessageBuilder::WriteToLogFile() { 221 DCHECK(pos_ <= Log::kMessageBufferSize); 222 // Assert that we do not already have a new line at the end. 223 DCHECK(pos_ == 0 || log_->message_buffer_[pos_ - 1] != '\n'); 224 if (pos_ == Log::kMessageBufferSize) pos_--; 225 log_->message_buffer_[pos_++] = '\n'; 226 const int written = log_->WriteToFile(log_->message_buffer_, pos_); 227 if (written != pos_) { 228 log_->stop(); 229 log_->logger_->LogFailure(); 230 } 231 } 232 233 234 } } // namespace v8::internal 235