OLD | NEW |
1 // Copyright 2009 the V8 project authors. All rights reserved. | 1 // Copyright 2009 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 13 matching lines...) Expand all Loading... |
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 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. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 | 27 |
28 #include <stdarg.h> | 28 #include <stdarg.h> |
29 | 29 |
30 #include "v8.h" | 30 #include "v8.h" |
31 | 31 |
32 #include "bootstrapper.h" | 32 #include "bootstrapper.h" |
33 #include "log.h" | 33 #include "log.h" |
| 34 #include "log-utils.h" |
34 #include "macro-assembler.h" | 35 #include "macro-assembler.h" |
35 #include "platform.h" | 36 #include "platform.h" |
36 #include "serialize.h" | 37 #include "serialize.h" |
37 #include "string-stream.h" | 38 #include "string-stream.h" |
38 | 39 |
39 namespace v8 { | 40 namespace v8 { |
40 namespace internal { | 41 namespace internal { |
41 | 42 |
42 #ifdef ENABLE_LOGGING_AND_PROFILING | 43 #ifdef ENABLE_LOGGING_AND_PROFILING |
43 | 44 |
(...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
280 void Profiler::Run() { | 281 void Profiler::Run() { |
281 TickSample sample; | 282 TickSample sample; |
282 bool overflow = Logger::profiler_->Remove(&sample); | 283 bool overflow = Logger::profiler_->Remove(&sample); |
283 while (running_) { | 284 while (running_) { |
284 LOG(TickEvent(&sample, overflow)); | 285 LOG(TickEvent(&sample, overflow)); |
285 overflow = Logger::profiler_->Remove(&sample); | 286 overflow = Logger::profiler_->Remove(&sample); |
286 } | 287 } |
287 } | 288 } |
288 | 289 |
289 | 290 |
290 #ifdef ENABLE_LOGGING_AND_PROFILING | |
291 | |
292 // Functions and data for performing output of log messages. | |
293 class Log : public AllStatic { | |
294 public: | |
295 // Opens stdout for logging. | |
296 static void OpenStdout(); | |
297 | |
298 // Opens file for logging. | |
299 static void OpenFile(const char* name); | |
300 | |
301 // Opens memory buffer for logging. | |
302 static void OpenMemoryBuffer(); | |
303 | |
304 // Frees all resources acquired in Open... functions. | |
305 static void Close(); | |
306 | |
307 // See description in include/v8.h. | |
308 static int GetLogLines(int from_pos, char* dest_buf, int max_size); | |
309 | |
310 // Returns whether logging is enabled. | |
311 static bool IsEnabled() { | |
312 return output_handle_ != NULL || output_buffer_ != NULL; | |
313 } | |
314 | |
315 private: | |
316 typedef int (*WritePtr)(const char* msg, int length); | |
317 | |
318 // Initialization function called from Open... functions. | |
319 static void Init(); | |
320 | |
321 // Write functions assume that mutex_ is acquired by the caller. | |
322 static WritePtr Write; | |
323 | |
324 // Implementation of writing to a log file. | |
325 static int WriteToFile(const char* msg, int length) { | |
326 ASSERT(output_handle_ != NULL); | |
327 int rv = fwrite(msg, 1, length, output_handle_); | |
328 ASSERT(length == rv); | |
329 return rv; | |
330 } | |
331 | |
332 // Implementation of writing to a memory buffer. | |
333 static int WriteToMemory(const char* msg, int length) { | |
334 ASSERT(output_buffer_ != NULL); | |
335 ASSERT(output_buffer_write_pos_ >= output_buffer_); | |
336 if (output_buffer_write_pos_ + length | |
337 <= output_buffer_ + kOutputBufferSize) { | |
338 memcpy(output_buffer_write_pos_, msg, length); | |
339 output_buffer_write_pos_ += length; | |
340 return length; | |
341 } else { | |
342 // Memory buffer is full, ignore write. | |
343 return 0; | |
344 } | |
345 } | |
346 | |
347 // When logging is active, either output_handle_ or output_buffer_ is used | |
348 // to store a pointer to log destination. If logging was opened via OpenStdout | |
349 // or OpenFile, then output_handle_ is used. If logging was opened | |
350 // via OpenMemoryBuffer, then output_buffer_ is used. | |
351 // mutex_ should be acquired before using output_handle_ or output_buffer_. | |
352 static FILE* output_handle_; | |
353 | |
354 static char* output_buffer_; | |
355 | |
356 // mutex_ is a Mutex used for enforcing exclusive | |
357 // access to the formatting buffer and the log file or log memory buffer. | |
358 static Mutex* mutex_; | |
359 | |
360 // Size of buffer used for memory logging. | |
361 static const int kOutputBufferSize = 2 * 1024 * 1024; | |
362 | |
363 // Writing position in a memory buffer. | |
364 static char* output_buffer_write_pos_; | |
365 | |
366 // Size of buffer used for formatting log messages. | |
367 static const int kMessageBufferSize = 2048; | |
368 | |
369 // Buffer used for formatting log messages. This is a singleton buffer and | |
370 // mutex_ should be acquired before using it. | |
371 static char* message_buffer_; | |
372 | |
373 friend class LogMessageBuilder; | |
374 }; | |
375 | |
376 | |
377 Log::WritePtr Log::Write = NULL; | |
378 FILE* Log::output_handle_ = NULL; | |
379 char* Log::output_buffer_ = NULL; | |
380 Mutex* Log::mutex_ = NULL; | |
381 char* Log::output_buffer_write_pos_ = NULL; | |
382 char* Log::message_buffer_ = NULL; | |
383 | |
384 | |
385 void Log::Init() { | |
386 mutex_ = OS::CreateMutex(); | |
387 message_buffer_ = NewArray<char>(kMessageBufferSize); | |
388 } | |
389 | |
390 | |
391 void Log::OpenStdout() { | |
392 ASSERT(!IsEnabled()); | |
393 output_handle_ = stdout; | |
394 Write = WriteToFile; | |
395 Init(); | |
396 } | |
397 | |
398 | |
399 void Log::OpenFile(const char* name) { | |
400 ASSERT(!IsEnabled()); | |
401 output_handle_ = OS::FOpen(name, OS::LogFileOpenMode); | |
402 Write = WriteToFile; | |
403 Init(); | |
404 } | |
405 | |
406 | |
407 void Log::OpenMemoryBuffer() { | |
408 ASSERT(!IsEnabled()); | |
409 output_buffer_ = NewArray<char>(kOutputBufferSize); | |
410 output_buffer_write_pos_ = output_buffer_; | |
411 Write = WriteToMemory; | |
412 Init(); | |
413 } | |
414 | |
415 | |
416 void Log::Close() { | |
417 if (Write == WriteToFile) { | |
418 fclose(output_handle_); | |
419 output_handle_ = NULL; | |
420 } else if (Write == WriteToMemory) { | |
421 DeleteArray(output_buffer_); | |
422 output_buffer_ = NULL; | |
423 } else { | |
424 ASSERT(Write == NULL); | |
425 } | |
426 Write = NULL; | |
427 | |
428 delete mutex_; | |
429 mutex_ = NULL; | |
430 | |
431 DeleteArray(message_buffer_); | |
432 message_buffer_ = NULL; | |
433 } | |
434 | |
435 | |
436 int Log::GetLogLines(int from_pos, char* dest_buf, int max_size) { | |
437 if (Write != WriteToMemory) return 0; | |
438 ASSERT(output_buffer_ != NULL); | |
439 ASSERT(output_buffer_write_pos_ >= output_buffer_); | |
440 ASSERT(from_pos >= 0); | |
441 ASSERT(max_size >= 0); | |
442 int actual_size = max_size; | |
443 char* buffer_read_pos = output_buffer_ + from_pos; | |
444 ScopedLock sl(mutex_); | |
445 if (actual_size == 0 | |
446 || output_buffer_write_pos_ == output_buffer_ | |
447 || buffer_read_pos >= output_buffer_write_pos_) { | |
448 // No data requested or can be returned. | |
449 return 0; | |
450 } | |
451 if (buffer_read_pos + actual_size > output_buffer_write_pos_) { | |
452 // Requested size overlaps with current writing position and | |
453 // needs to be truncated. | |
454 actual_size = output_buffer_write_pos_ - buffer_read_pos; | |
455 ASSERT(actual_size == 0 || buffer_read_pos[actual_size - 1] == '\n'); | |
456 } else { | |
457 // Find previous log line boundary. | |
458 char* end_pos = buffer_read_pos + actual_size - 1; | |
459 while (end_pos >= buffer_read_pos && *end_pos != '\n') --end_pos; | |
460 actual_size = end_pos - buffer_read_pos + 1; | |
461 } | |
462 ASSERT(actual_size <= max_size); | |
463 if (actual_size > 0) { | |
464 memcpy(dest_buf, buffer_read_pos, actual_size); | |
465 } | |
466 return actual_size; | |
467 } | |
468 | |
469 | |
470 // Utility class for formatting log messages. It fills the message into the | |
471 // static buffer in Log. | |
472 class LogMessageBuilder BASE_EMBEDDED { | |
473 public: | |
474 explicit LogMessageBuilder(); | |
475 ~LogMessageBuilder() { } | |
476 | |
477 void Append(const char* format, ...); | |
478 void Append(const char* format, va_list args); | |
479 void Append(const char c); | |
480 void Append(String* str); | |
481 void AppendDetailed(String* str, bool show_impl_info); | |
482 | |
483 void WriteToLogFile(); | |
484 void WriteCStringToLogFile(const char* str); | |
485 | |
486 private: | |
487 ScopedLock sl; | |
488 int pos_; | |
489 }; | |
490 | |
491 | |
492 // Create a message builder starting from position 0. This acquires the mutex | |
493 // in the logger as well. | |
494 LogMessageBuilder::LogMessageBuilder(): sl(Log::mutex_), pos_(0) { | |
495 ASSERT(Log::message_buffer_ != NULL); | |
496 } | |
497 | |
498 | |
499 // Append string data to the log message. | |
500 void LogMessageBuilder::Append(const char* format, ...) { | |
501 Vector<char> buf(Log::message_buffer_ + pos_, | |
502 Log::kMessageBufferSize - pos_); | |
503 va_list args; | |
504 va_start(args, format); | |
505 Append(format, args); | |
506 va_end(args); | |
507 ASSERT(pos_ <= Log::kMessageBufferSize); | |
508 } | |
509 | |
510 | |
511 // Append string data to the log message. | |
512 void LogMessageBuilder::Append(const char* format, va_list args) { | |
513 Vector<char> buf(Log::message_buffer_ + pos_, | |
514 Log::kMessageBufferSize - pos_); | |
515 int result = v8::internal::OS::VSNPrintF(buf, format, args); | |
516 | |
517 // Result is -1 if output was truncated. | |
518 if (result >= 0) { | |
519 pos_ += result; | |
520 } else { | |
521 pos_ = Log::kMessageBufferSize; | |
522 } | |
523 ASSERT(pos_ <= Log::kMessageBufferSize); | |
524 } | |
525 | |
526 | |
527 // Append a character to the log message. | |
528 void LogMessageBuilder::Append(const char c) { | |
529 if (pos_ < Log::kMessageBufferSize) { | |
530 Log::message_buffer_[pos_++] = c; | |
531 } | |
532 ASSERT(pos_ <= Log::kMessageBufferSize); | |
533 } | |
534 | |
535 | |
536 // Append a heap string. | |
537 void LogMessageBuilder::Append(String* str) { | |
538 AssertNoAllocation no_heap_allocation; // Ensure string stay valid. | |
539 int length = str->length(); | |
540 for (int i = 0; i < length; i++) { | |
541 Append(static_cast<char>(str->Get(i))); | |
542 } | |
543 } | |
544 | |
545 void LogMessageBuilder::AppendDetailed(String* str, bool show_impl_info) { | |
546 AssertNoAllocation no_heap_allocation; // Ensure string stay valid. | |
547 int len = str->length(); | |
548 if (len > 0x1000) | |
549 len = 0x1000; | |
550 if (show_impl_info) { | |
551 Append(str->IsAsciiRepresentation() ? 'a' : '2'); | |
552 if (StringShape(str).IsExternal()) | |
553 Append('e'); | |
554 if (StringShape(str).IsSymbol()) | |
555 Append('#'); | |
556 Append(":%i:", str->length()); | |
557 } | |
558 for (int i = 0; i < len; i++) { | |
559 uc32 c = str->Get(i); | |
560 if (c > 0xff) { | |
561 Append("\\u%04x", c); | |
562 } else if (c < 32 || c > 126) { | |
563 Append("\\x%02x", c); | |
564 } else if (c == ',') { | |
565 Append("\\,"); | |
566 } else if (c == '\\') { | |
567 Append("\\\\"); | |
568 } else { | |
569 Append("%lc", c); | |
570 } | |
571 } | |
572 } | |
573 | |
574 // Write the log message to the log file currently opened. | |
575 void LogMessageBuilder::WriteToLogFile() { | |
576 ASSERT(pos_ <= Log::kMessageBufferSize); | |
577 Log::Write(Log::message_buffer_, pos_); | |
578 } | |
579 | |
580 // Write a null-terminated string to to the log file currently opened. | |
581 void LogMessageBuilder::WriteCStringToLogFile(const char* str) { | |
582 int len = strlen(str); | |
583 Log::Write(str, len); | |
584 } | |
585 #endif | |
586 | |
587 | |
588 // | 291 // |
589 // Logger class implementation. | 292 // Logger class implementation. |
590 // | 293 // |
591 Ticker* Logger::ticker_ = NULL; | 294 Ticker* Logger::ticker_ = NULL; |
592 Profiler* Logger::profiler_ = NULL; | 295 Profiler* Logger::profiler_ = NULL; |
593 VMState* Logger::current_state_ = NULL; | 296 VMState* Logger::current_state_ = NULL; |
594 VMState Logger::bottom_state_(EXTERNAL); | 297 VMState Logger::bottom_state_(EXTERNAL); |
595 SlidingStateWindow* Logger::sliding_state_window_ = NULL; | 298 SlidingStateWindow* Logger::sliding_state_window_ = NULL; |
596 | 299 |
597 | 300 |
(...skipping 816 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1414 } else if (previous_->state_ == EXTERNAL) { | 1117 } else if (previous_->state_ == EXTERNAL) { |
1415 // We are leaving V8. | 1118 // We are leaving V8. |
1416 Heap::Protect(); | 1119 Heap::Protect(); |
1417 } | 1120 } |
1418 } | 1121 } |
1419 #endif | 1122 #endif |
1420 } | 1123 } |
1421 #endif | 1124 #endif |
1422 | 1125 |
1423 } } // namespace v8::internal | 1126 } } // namespace v8::internal |
OLD | NEW |