From c5d98b775daaa6d5f9dd17517e616ebe54e8e231 Mon Sep 17 00:00:00 2001 From: "lrn@chromium.org" Date: Thu, 11 Sep 2008 11:24:45 +0000 Subject: [PATCH] Added -log-regexp option to log all compilations and executions of regular expressions. Slightly modified SmartPointer. Made String.ToWideCString return a SmartPointer instead of a plain pointer. git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@271 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/jsregexp.cc | 4 +++ src/log.cc | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++- src/log.h | 13 ++++++++++ src/messages.cc | 2 +- src/objects.cc | 6 ++--- src/objects.h | 2 +- src/smart-pointer.h | 31 +++++++++++++--------- 7 files changed, 114 insertions(+), 18 deletions(-) diff --git a/src/jsregexp.cc b/src/jsregexp.cc index 51bfd37..b59a3af 100644 --- a/src/jsregexp.cc +++ b/src/jsregexp.cc @@ -205,6 +205,8 @@ Handle RegExpImpl::JsreCompile(Handle re, value->set(INTERNAL_INDEX, *internal); re->set_value(*value); + LOG(RegExpCompileEvent(re)); + return re; } @@ -223,6 +225,8 @@ Handle RegExpImpl::JsreExecOnce(Handle regexp, const JSRegExp* js_regexp = reinterpret_cast(internal->GetDataStartAddress()); + LOG(RegExpExecEvent(regexp, previous_index, subject)); + rc = jsRegExpExecute(js_regexp, two_byte_subject, subject->length(), previous_index, diff --git a/src/log.cc b/src/log.cc index dbefc04..a7bb406 100644 --- a/src/log.cc +++ b/src/log.cc @@ -52,6 +52,8 @@ DEFINE_bool(log_state_changes, false, "Log state changes."); DEFINE_bool(log_suspect, false, "Log suspect operations."); DEFINE_bool(prof, false, "Log statistical profiling information (implies --log-code)."); +DEFINE_bool(log_regexp, false, + "Log regular expression execution."); DEFINE_bool(sliding_state_window, false, "Update sliding state window counters."); @@ -368,6 +370,75 @@ void Logger::SharedLibraryEvent(const wchar_t* library_path, #endif } +void Logger::LogRegExpSource(Handle regexp) { + // Prints "/" + re.source + "/" + + // (re.global?"g":"") + (re.ignorecase?"i":"") + (re.multiline?"m":"") + + Handle source = GetProperty(regexp, "source"); + if (!source->IsString()) { + fprintf(logfile_, "no source"); + return; + } + Handle source_string = Handle::cast(source); + + SmartPointer cstring = source_string->ToWideCString(); + fprintf(logfile_, "/"); + for (int i = 0, n = source_string->length(); i < n; i++) { + uc16 c = cstring[i]; + if (c < 32 || (c > 126 && c <= 255)) { + fprintf(logfile_, "\\x%02x", c); + } else if (c > 255) { + fprintf(logfile_, "\\u%04x", c); + } else { + fprintf(logfile_, "%lc", c); + } + } + fprintf(logfile_, "/"); + + // global flag + Handle global = GetProperty(regexp, "global"); + if (global->IsTrue()) { + fprintf(logfile_, "g"); + } + // ignorecase flag + Handle ignorecase = GetProperty(regexp, "ignoreCase"); + if (ignorecase->IsTrue()) { + fprintf(logfile_, "i"); + } + // multiline flag + Handle multiline = GetProperty(regexp, "multiline"); + if (multiline->IsTrue()) { + fprintf(logfile_, "m"); + } +} + + +void Logger::RegExpCompileEvent(Handle regexp) { +#ifdef ENABLE_LOGGING_AND_PROFILING + if (logfile_ == NULL || !FLAG_log_regexp) return; + ScopedLock sl(mutex_); + + fprintf(logfile_, "regexp-compile,"); + LogRegExpSource(regexp); + fprintf(logfile_, "\n"); +#endif +} + + +void Logger::RegExpExecEvent(Handle regexp, + int start_index, + Handle string) { +#ifdef ENABLE_LOGGING_AND_PROFILING + if (logfile_ == NULL || !FLAG_log_regexp) return; + ScopedLock sl(mutex_); + + fprintf(logfile_, "regexp-run,"); + LogRegExpSource(regexp); + fprintf(logfile_, ",0x%08x,%d..%d\n", string->Hash(), start_index, string->length()); +#endif +} + + void Logger::ApiIndexedSecurityCheck(uint32_t index) { #ifdef ENABLE_LOGGING_AND_PROFILING if (logfile_ == NULL || !FLAG_log_api) return; @@ -612,6 +683,7 @@ bool Logger::Setup() { FLAG_log_gc = true; FLAG_log_suspect = true; FLAG_log_handles = true; + FLAG_log_regexp = true; } // --prof implies --log-code. @@ -620,7 +692,7 @@ bool Logger::Setup() { // Each of the individual log flags implies --log. Check after // checking --log-all and --prof in case they set --log-code. if (FLAG_log_api || FLAG_log_code || FLAG_log_gc || - FLAG_log_handles || FLAG_log_suspect) { + FLAG_log_handles || FLAG_log_suspect || FLAG_log_regexp) { FLAG_log = true; } diff --git a/src/log.h b/src/log.h index 1c9d0b6..267b1bd 100644 --- a/src/log.h +++ b/src/log.h @@ -174,6 +174,15 @@ class Logger { unsigned start, unsigned end); + // ==== Events logged by --log-regexp ==== + // Regexp compilation and execution events. + + static void RegExpCompileEvent(Handle regexp); + + static void RegExpExecEvent(Handle regexp, + int start_index, + Handle string); + #ifdef ENABLE_LOGGING_AND_PROFILING static StateTag state() { return current_state_ ? current_state_->state() : OTHER; @@ -182,6 +191,10 @@ class Logger { #ifdef ENABLE_LOGGING_AND_PROFILING private: + + // Emits the source code of a regexp. Used by regexp events. + static void Logger::LogRegExpSource(Handle regexp); + // Emits a profiler tick event. Used by the profiler thread. static void TickEvent(TickSample* sample, bool overflow); diff --git a/src/messages.cc b/src/messages.cc index 6e8a371..7e3c0d6 100644 --- a/src/messages.cc +++ b/src/messages.cc @@ -46,7 +46,7 @@ void MessageHandler::DefaultMessageReport(const MessageLocation* loc, } else { HandleScope scope; Handle data(loc->script()->name()); - SmartPointer data_str = NULL; + SmartPointer data_str; if (data->IsString()) data_str = Handle::cast(data)->ToCString(DISALLOW_NULLS); PrintF("%s:%i: %s\n", *data_str ? *data_str : "", diff --git a/src/objects.cc b/src/objects.cc index b2ace6e..46ac8f5 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -3023,11 +3023,11 @@ const uc16* String::GetTwoByteData(unsigned start) { } -uc16* String::ToWideCString(RobustnessFlag robust_flag) { +SmartPointer String::ToWideCString(RobustnessFlag robust_flag) { ASSERT(NativeAllocationChecker::allocation_allowed()); if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) { - return NULL; + return SmartPointer(); } Access buffer(&string_input_buffer); @@ -3041,7 +3041,7 @@ uc16* String::ToWideCString(RobustnessFlag robust_flag) { result[i++] = character; } result[i] = 0; - return result; + return SmartPointer(result); } diff --git a/src/objects.h b/src/objects.h index 742e4f3..fc7256e 100644 --- a/src/objects.h +++ b/src/objects.h @@ -2861,7 +2861,7 @@ class String: public HeapObject { // ROBUST_STRING_TRAVERSAL invokes behaviour that is robust This means it // handles unexpected data without causing assert failures and it does not // do any heap allocations. This is useful when printing stack traces. - uc16* ToWideCString(RobustnessFlag robustness_flag = FAST_STRING_TRAVERSAL); + SmartPointer ToWideCString(RobustnessFlag robustness_flag = FAST_STRING_TRAVERSAL); // Tells whether the hash code has been computed. inline bool HasHashCode(); diff --git a/src/smart-pointer.h b/src/smart-pointer.h index accbe03..4ae0524 100644 --- a/src/smart-pointer.h +++ b/src/smart-pointer.h @@ -31,19 +31,18 @@ namespace v8 { namespace internal { -// A 'scoped pointer' that calls delete[] on its pointer when the +// A 'scoped array pointer' that calls DeleteArray on its pointer when the // destructor is called. template class SmartPointer { public: - // Construct a scoped pointer from a plain one. - inline SmartPointer(T* pointer) : p(pointer) {} + // Default constructor. Construct an empty scoped pointer. + inline SmartPointer() : p(NULL) {} - // When the destructor of the scoped pointer is executed the plain pointer - // is deleted using DeleteArray. This implies that you must allocate with - // NewArray. - inline ~SmartPointer() { if (p) DeleteArray(p); } + + // Construct a scoped pointer from a plain one. + explicit inline SmartPointer(T* pointer) : p(pointer) {} // Copy constructor removes the pointer from the original to avoid double @@ -53,13 +52,20 @@ class SmartPointer { } + // When the destructor of the scoped pointer is executed the plain pointer + // is deleted using DeleteArray. This implies that you must allocate with + // NewArray. + inline ~SmartPointer() { if (p) DeleteArray(p); } + + // You can get the underlying pointer out with the * operator. inline T* operator*() { return p; } - // You can use -> as if it was a plain pointer. - inline T* operator->() { return p; } - + // You can use [n] to index as if it was a plain pointer + inline T& operator[](size_t i) { + return p[i]; + } // We don't have implicit conversion to a T* since that hinders migration: // You would not be able to change a method from returning a T* to @@ -80,9 +86,10 @@ class SmartPointer { // the copy constructor it removes the pointer in the original to avoid // double freeing. inline SmartPointer& operator=(const SmartPointer& rhs) { - ASSERT(p == NULL); - p = rhs.p; + ASSERT(p == NULL); + T* tmp = rhs.p; // swap to handle self-assignment const_cast&>(rhs).p = NULL; + p = tmp; return *this; } -- 2.7.4