• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
Log(Logger * logger)18 Log::Log(Logger* logger)
19   : is_stopped_(false),
20     output_handle_(NULL),
21     message_buffer_(NULL),
22     logger_(logger) {
23 }
24 
25 
Initialize(const char * log_file_name)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 
OpenStdout()56 void Log::OpenStdout() {
57   DCHECK(!IsEnabled());
58   output_handle_ = stdout;
59 }
60 
61 
OpenTemporaryFile()62 void Log::OpenTemporaryFile() {
63   DCHECK(!IsEnabled());
64   output_handle_ = base::OS::OpenTemporaryFile();
65 }
66 
67 
OpenFile(const char * name)68 void Log::OpenFile(const char* name) {
69   DCHECK(!IsEnabled());
70   output_handle_ = base::OS::FOpen(name, base::OS::LogFileOpenMode);
71 }
72 
73 
Close()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 
MessageBuilder(Log * log)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 
Append(const char * format,...)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 
AppendVA(const char * format,va_list args)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 
Append(const char c)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 
AppendDoubleQuotedString(const char * string)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 
Append(String * str)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 
AppendAddress(Address addr)156 void Log::MessageBuilder::AppendAddress(Address addr) {
157   Append("0x%" V8PRIxPTR, addr);
158 }
159 
160 
AppendSymbolName(Symbol * symbol)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 
AppendDetailed(String * str,bool show_impl_info)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 
AppendStringPart(const char * str,int len)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 
WriteToLogFile()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