Added -log-regexp option to log all compilations and executions of regular expressions.
authorlrn@chromium.org <lrn@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 11 Sep 2008 11:24:45 +0000 (11:24 +0000)
committerlrn@chromium.org <lrn@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 11 Sep 2008 11:24:45 +0000 (11:24 +0000)
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
src/log.cc
src/log.h
src/messages.cc
src/objects.cc
src/objects.h
src/smart-pointer.h

index 51bfd37..b59a3af 100644 (file)
@@ -205,6 +205,8 @@ Handle<Object> RegExpImpl::JsreCompile(Handle<JSValue> re,
   value->set(INTERNAL_INDEX, *internal);
   re->set_value(*value);
 
+  LOG(RegExpCompileEvent(re));
+
   return re;
 }
 
@@ -223,6 +225,8 @@ Handle<Object> RegExpImpl::JsreExecOnce(Handle<JSValue> regexp,
     const JSRegExp* js_regexp =
         reinterpret_cast<JSRegExp*>(internal->GetDataStartAddress());
 
+    LOG(RegExpExecEvent(regexp, previous_index, subject));
+
     rc = jsRegExpExecute(js_regexp, two_byte_subject,
                        subject->length(),
                        previous_index,
index dbefc04..a7bb406 100644 (file)
@@ -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<JSValue> regexp) {
+  // Prints "/" + re.source + "/" + 
+  //      (re.global?"g":"") + (re.ignorecase?"i":"") + (re.multiline?"m":"")
+
+  Handle<Object> source = GetProperty(regexp, "source");
+  if (!source->IsString()) {
+    fprintf(logfile_, "no source");
+    return;
+  }
+  Handle<String> source_string = Handle<String>::cast(source);
+
+  SmartPointer<uc16> 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<Object> global = GetProperty(regexp, "global");
+  if (global->IsTrue()) {
+    fprintf(logfile_, "g");
+  }
+  // ignorecase flag
+  Handle<Object> ignorecase = GetProperty(regexp, "ignoreCase");
+  if (ignorecase->IsTrue()) {
+    fprintf(logfile_, "i");
+  }
+  // multiline flag
+  Handle<Object> multiline = GetProperty(regexp, "multiline");
+  if (multiline->IsTrue()) {
+    fprintf(logfile_, "m");
+  }
+}
+
+
+void Logger::RegExpCompileEvent(Handle<JSValue> 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<JSValue> regexp,
+                             int start_index,
+                             Handle<String> 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;
   }
 
index 1c9d0b6..267b1bd 100644 (file)
--- 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<JSValue> regexp);
+
+  static void RegExpExecEvent(Handle<JSValue> regexp, 
+                              int start_index, 
+                              Handle<String> 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<JSValue> regexp);
+
   // Emits a profiler tick event. Used by the profiler thread.
   static void TickEvent(TickSample* sample, bool overflow);
 
index 6e8a371..7e3c0d6 100644 (file)
@@ -46,7 +46,7 @@ void MessageHandler::DefaultMessageReport(const MessageLocation* loc,
   } else {
     HandleScope scope;
     Handle<Object> data(loc->script()->name());
-    SmartPointer<char> data_str = NULL;
+    SmartPointer<char> data_str;
     if (data->IsString())
       data_str = Handle<String>::cast(data)->ToCString(DISALLOW_NULLS);
     PrintF("%s:%i: %s\n", *data_str ? *data_str : "<unknown>",
index b2ace6e..46ac8f5 100644 (file)
@@ -3023,11 +3023,11 @@ const uc16* String::GetTwoByteData(unsigned start) {
 }
 
 
-uc16* String::ToWideCString(RobustnessFlag robust_flag) {
+SmartPointer<uc16> String::ToWideCString(RobustnessFlag robust_flag) {
   ASSERT(NativeAllocationChecker::allocation_allowed());
 
   if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
-    return NULL;
+    return SmartPointer<uc16>();
   }
 
   Access<StringInputBuffer> buffer(&string_input_buffer);
@@ -3041,7 +3041,7 @@ uc16* String::ToWideCString(RobustnessFlag robust_flag) {
     result[i++] = character;
   }
   result[i] = 0;
-  return result;
+  return SmartPointer<uc16>(result);
 }
 
 
index 742e4f3..fc7256e 100644 (file)
@@ -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<uc16> ToWideCString(RobustnessFlag robustness_flag = FAST_STRING_TRAVERSAL);
 
   // Tells whether the hash code has been computed.
   inline bool HasHashCode();
index accbe03..4ae0524 100644 (file)
 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<typename T>
 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<T>& rhs) {
-    ASSERT(p == NULL);
-    p = rhs.p;
+    ASSERT(p == NULL);  
+    T* tmp = rhs.p; // swap to handle self-assignment
     const_cast<SmartPointer<T>&>(rhs).p = NULL;
+    p = tmp;
     return *this;
   }