| 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 |