v8  3.14.5(node0.10.28)
V8 is Google's open source JavaScript engine
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
log-utils.cc
Go to the documentation of this file.
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 
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 
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 
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 
138 void Log::OpenStdout() {
139  ASSERT(!IsEnabled());
140  output_handle_ = stdout;
141 }
142 
143 
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 
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 
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 
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 
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);
213 }
214 
215 
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 {
226  }
228 }
229 
230 
231 void LogMessageBuilder::Append(const char c) {
232  if (pos_ < Log::kMessageBufferSize) {
233  log_->message_buffer_[pos_++] = c;
234  }
236 }
237 
238 
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 
248 void LogMessageBuilder::AppendAddress(Address addr) {
249  Append("0x%" V8PRIxPTR, addr);
250 }
251 
252 
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 
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;
297 }
298 
299 
300 void LogMessageBuilder::WriteToLogFile() {
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
byte * Address
Definition: globals.h:157
#define V8PRIxPTR
Definition: globals.h:189
static int VSNPrintF(Vector< char > str, const char *format, va_list args)
static const char *const kLogToTemporaryFile
Definition: log-utils.h:62
static FILE * OpenTemporaryFile()
int32_t uc32
Definition: globals.h:260
#define ASSERT(condition)
Definition: checks.h:270
void Add(Vector< const char > format, Vector< FmtElm > elms)
static FILE * FOpen(const char *path, const char *mode)
static const int kMessageBufferSize
Definition: log-utils.h:58
bool IsEnabled()
Definition: log-utils.h:53
static Mutex * CreateMutex()
static double TimeCurrentMillis()
activate correct semantics for inheriting readonliness false
Definition: flags.cc:141
static void StrNCpy(Vector< char > dest, const char *src, size_t n)
activate correct semantics for inheriting readonliness enable harmony semantics for typeof enable harmony enable harmony proxies enable all harmony harmony_scoping harmony_proxies harmony_scoping tracks arrays with only smi values automatically unbox arrays of doubles use crankshaft use hydrogen range analysis use hydrogen global value numbering use function inlining maximum number of AST nodes considered for a single inlining loop invariant code motion print statistics for hydrogen trace generated IR for specified phases trace register allocator trace range analysis trace representation types environment for every instruction put a break point before deoptimizing polymorphic inlining perform array bounds checks elimination use dead code elimination trace on stack replacement optimize closures cache optimized code for closures functions with arguments object loop weight for representation inference allow uint32 values on optimize frames if they are used only in safe operations track parallel recompilation enable all profiler experiments number of stack frames inspected by the profiler call recompile stub directly when self optimizing trigger profiler ticks based on counting instead of timing weight back edges by jump distance for interrupt triggering percentage of ICs that must have type info to allow optimization watch_ic_patching retry_self_opt interrupt_at_exit extra verbose compilation tracing generate extra emit comments in code disassembly enable use of SSE3 instructions if available enable use of CMOV instruction if available enable use of SAHF instruction if enable use of VFP3 instructions if available this implies enabling ARMv7 and VFP2 enable use of VFP2 instructions if available enable use of SDIV and UDIV instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of MIPS FPU instructions if NULL
Definition: flags.cc:301
SmartArrayPointer< const char > ToCString() const
void DeleteArray(T *array)
Definition: allocation.h:91
static const char *const LogFileOpenMode
Definition: platform.h:186
const int MB
Definition: globals.h:208