• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 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 #include "v8.h"
29 
30 #include "log-utils.h"
31 #include "string-stream.h"
32 
33 namespace v8 {
34 namespace internal {
35 
36 
37 const char* const Log::kLogToTemporaryFile = "&";
38 
39 
Log(Logger * logger)40 Log::Log(Logger* logger)
41   : is_stopped_(false),
42     output_handle_(NULL),
43     ll_output_handle_(NULL),
44     mutex_(NULL),
45     message_buffer_(NULL),
46     logger_(logger) {
47 }
48 
49 
AddIsolateIdIfNeeded(StringStream * stream)50 static void AddIsolateIdIfNeeded(StringStream* stream) {
51   Isolate* isolate = Isolate::Current();
52   if (isolate->IsDefaultIsolate()) return;
53   stream->Add("isolate-%p-", isolate);
54 }
55 
56 
Initialize()57 void Log::Initialize() {
58   mutex_ = OS::CreateMutex();
59   message_buffer_ = NewArray<char>(kMessageBufferSize);
60 
61   // --log-all enables all the log flags.
62   if (FLAG_log_all) {
63     FLAG_log_runtime = true;
64     FLAG_log_api = true;
65     FLAG_log_code = true;
66     FLAG_log_gc = true;
67     FLAG_log_suspect = true;
68     FLAG_log_handles = true;
69     FLAG_log_regexp = true;
70   }
71 
72   // --prof implies --log-code.
73   if (FLAG_prof) FLAG_log_code = true;
74 
75   // --prof_lazy controls --log-code, implies --noprof_auto.
76   if (FLAG_prof_lazy) {
77     FLAG_log_code = false;
78     FLAG_prof_auto = false;
79   }
80 
81   bool open_log_file = FLAG_log || FLAG_log_runtime || FLAG_log_api
82       || FLAG_log_code || FLAG_log_gc || FLAG_log_handles || FLAG_log_suspect
83       || FLAG_log_regexp || FLAG_log_state_changes || FLAG_ll_prof;
84 
85   // If we're logging anything, we need to open the log file.
86   if (open_log_file) {
87     if (strcmp(FLAG_logfile, "-") == 0) {
88       OpenStdout();
89     } else if (strcmp(FLAG_logfile, kLogToTemporaryFile) == 0) {
90       OpenTemporaryFile();
91     } else {
92       if (strchr(FLAG_logfile, '%') != NULL ||
93           !Isolate::Current()->IsDefaultIsolate()) {
94         // If there's a '%' in the log file name we have to expand
95         // placeholders.
96         HeapStringAllocator allocator;
97         StringStream stream(&allocator);
98         AddIsolateIdIfNeeded(&stream);
99         for (const char* p = FLAG_logfile; *p; p++) {
100           if (*p == '%') {
101             p++;
102             switch (*p) {
103               case '\0':
104                 // If there's a % at the end of the string we back up
105                 // one character so we can escape the loop properly.
106                 p--;
107                 break;
108               case 't': {
109                 // %t expands to the current time in milliseconds.
110                 double time = OS::TimeCurrentMillis();
111                 stream.Add("%.0f", FmtElm(time));
112                 break;
113               }
114               case '%':
115                 // %% expands (contracts really) to %.
116                 stream.Put('%');
117                 break;
118               default:
119                 // All other %'s expand to themselves.
120                 stream.Put('%');
121                 stream.Put(*p);
122                 break;
123             }
124           } else {
125             stream.Put(*p);
126           }
127         }
128         SmartArrayPointer<const char> expanded = stream.ToCString();
129         OpenFile(*expanded);
130       } else {
131         OpenFile(FLAG_logfile);
132       }
133     }
134   }
135 }
136 
137 
OpenStdout()138 void Log::OpenStdout() {
139   ASSERT(!IsEnabled());
140   output_handle_ = stdout;
141 }
142 
143 
OpenTemporaryFile()144 void Log::OpenTemporaryFile() {
145   ASSERT(!IsEnabled());
146   output_handle_ = i::OS::OpenTemporaryFile();
147 }
148 
149 
150 // Extension added to V8 log file name to get the low-level log name.
151 static const char kLowLevelLogExt[] = ".ll";
152 
153 // File buffer size of the low-level log. We don't use the default to
154 // minimize the associated overhead.
155 static const int kLowLevelLogBufferSize = 2 * MB;
156 
157 
OpenFile(const char * name)158 void Log::OpenFile(const char* name) {
159   ASSERT(!IsEnabled());
160   output_handle_ = OS::FOpen(name, OS::LogFileOpenMode);
161   if (FLAG_ll_prof) {
162     // Open the low-level log file.
163     size_t len = strlen(name);
164     ScopedVector<char> ll_name(static_cast<int>(len + sizeof(kLowLevelLogExt)));
165     memcpy(ll_name.start(), name, len);
166     memcpy(ll_name.start() + len, kLowLevelLogExt, sizeof(kLowLevelLogExt));
167     ll_output_handle_ = OS::FOpen(ll_name.start(), OS::LogFileOpenMode);
168     setvbuf(ll_output_handle_, NULL, _IOFBF, kLowLevelLogBufferSize);
169   }
170 }
171 
172 
Close()173 FILE* Log::Close() {
174   FILE* result = NULL;
175   if (output_handle_ != NULL) {
176     if (strcmp(FLAG_logfile, kLogToTemporaryFile) != 0) {
177       fclose(output_handle_);
178     } else {
179       result = output_handle_;
180     }
181   }
182   output_handle_ = NULL;
183   if (ll_output_handle_ != NULL) fclose(ll_output_handle_);
184   ll_output_handle_ = NULL;
185 
186   DeleteArray(message_buffer_);
187   message_buffer_ = NULL;
188 
189   delete mutex_;
190   mutex_ = NULL;
191 
192   is_stopped_ = false;
193   return result;
194 }
195 
196 
LogMessageBuilder(Logger * logger)197 LogMessageBuilder::LogMessageBuilder(Logger* logger)
198   : log_(logger->log_),
199     sl(log_->mutex_),
200     pos_(0) {
201   ASSERT(log_->message_buffer_ != NULL);
202 }
203 
204 
Append(const char * format,...)205 void LogMessageBuilder::Append(const char* format, ...) {
206   Vector<char> buf(log_->message_buffer_ + pos_,
207                    Log::kMessageBufferSize - pos_);
208   va_list args;
209   va_start(args, format);
210   AppendVA(format, args);
211   va_end(args);
212   ASSERT(pos_ <= Log::kMessageBufferSize);
213 }
214 
215 
AppendVA(const char * format,va_list args)216 void LogMessageBuilder::AppendVA(const char* format, va_list args) {
217   Vector<char> buf(log_->message_buffer_ + pos_,
218                    Log::kMessageBufferSize - pos_);
219   int result = v8::internal::OS::VSNPrintF(buf, format, args);
220 
221   // Result is -1 if output was truncated.
222   if (result >= 0) {
223     pos_ += result;
224   } else {
225     pos_ = Log::kMessageBufferSize;
226   }
227   ASSERT(pos_ <= Log::kMessageBufferSize);
228 }
229 
230 
Append(const char c)231 void LogMessageBuilder::Append(const char c) {
232   if (pos_ < Log::kMessageBufferSize) {
233     log_->message_buffer_[pos_++] = c;
234   }
235   ASSERT(pos_ <= Log::kMessageBufferSize);
236 }
237 
238 
Append(String * str)239 void LogMessageBuilder::Append(String* str) {
240   AssertNoAllocation no_heap_allocation;  // Ensure string stay valid.
241   int length = str->length();
242   for (int i = 0; i < length; i++) {
243     Append(static_cast<char>(str->Get(i)));
244   }
245 }
246 
247 
AppendAddress(Address addr)248 void LogMessageBuilder::AppendAddress(Address addr) {
249   Append("0x%" V8PRIxPTR, addr);
250 }
251 
252 
AppendDetailed(String * str,bool show_impl_info)253 void LogMessageBuilder::AppendDetailed(String* str, bool show_impl_info) {
254   if (str == NULL) return;
255   AssertNoAllocation no_heap_allocation;  // Ensure string stay valid.
256   int len = str->length();
257   if (len > 0x1000)
258     len = 0x1000;
259   if (show_impl_info) {
260     Append(str->IsAsciiRepresentation() ? 'a' : '2');
261     if (StringShape(str).IsExternal())
262       Append('e');
263     if (StringShape(str).IsSymbol())
264       Append('#');
265     Append(":%i:", str->length());
266   }
267   for (int i = 0; i < len; i++) {
268     uc32 c = str->Get(i);
269     if (c > 0xff) {
270       Append("\\u%04x", c);
271     } else if (c < 32 || c > 126) {
272       Append("\\x%02x", c);
273     } else if (c == ',') {
274       Append("\\,");
275     } else if (c == '\\') {
276       Append("\\\\");
277     } else if (c == '\"') {
278       Append("\"\"");
279     } else {
280       Append("%lc", c);
281     }
282   }
283 }
284 
285 
AppendStringPart(const char * str,int len)286 void LogMessageBuilder::AppendStringPart(const char* str, int len) {
287   if (pos_ + len > Log::kMessageBufferSize) {
288     len = Log::kMessageBufferSize - pos_;
289     ASSERT(len >= 0);
290     if (len == 0) return;
291   }
292   Vector<char> buf(log_->message_buffer_ + pos_,
293                    Log::kMessageBufferSize - pos_);
294   OS::StrNCpy(buf, str, len);
295   pos_ += len;
296   ASSERT(pos_ <= Log::kMessageBufferSize);
297 }
298 
299 
WriteToLogFile()300 void LogMessageBuilder::WriteToLogFile() {
301   ASSERT(pos_ <= Log::kMessageBufferSize);
302   const int written = log_->WriteToFile(log_->message_buffer_, pos_);
303   if (written != pos_) {
304     log_->stop();
305     log_->logger_->LogFailure();
306   }
307 }
308 
309 
310 } }  // namespace v8::internal
311