Added runtime call to the logging infrastructure. Made some changes
authorchristian.plesner.hansen@gmail.com <christian.plesner.hansen@gmail.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 6 Jan 2009 13:24:52 +0000 (13:24 +0000)
committerchristian.plesner.hansen@gmail.com <christian.plesner.hansen@gmail.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 6 Jan 2009 13:24:52 +0000 (13:24 +0000)
to the way regexps are being logged.

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@1028 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

13 files changed:
src/codegen-arm.cc
src/codegen-arm.h
src/codegen-ia32.cc
src/codegen-ia32.h
src/codegen.cc
src/jsregexp.cc
src/log.cc
src/log.h
src/regexp-delay.js
src/runtime.cc
src/runtime.h
src/string.js
test/mjsunit/fuzz-natives.js

index 3453d52e5e85f06feeb816e125e45c6fd6fe9ff1..e0cae7f6e85d54cc0394c93ab4958fc5529bdcd9 100644 (file)
@@ -2577,6 +2577,19 @@ void CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) {
 }
 
 
+void CodeGenerator::GenerateLog(ZoneList<Expression*>* args) {
+  // See comment in CodeGenerator::GenerateLog in codegen-ia32.cc.
+  ASSERT_EQ(args->length(), 3);
+  if (ShouldGenerateLog(args->at(0))) {
+    Load(args->at(1));
+    Load(args->at(2));
+    __ CallRuntime(Runtime::kLog, 2);
+  }
+  __ mov(r0, Operand(Factory::undefined_value()));
+  frame_->Push(r0);
+}
+
+
 void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) {
   ASSERT(args->length() == 1);
   Load(args->at(0));
index 42a05eca6f5edebcefcb0fa1cbffcfe65d7b2b20..18f7a9212b643eaf1f384d024b97556f290d93c7 100644 (file)
@@ -195,6 +195,8 @@ class CodeGenerator: public AstVisitor {
                                Handle<Script> script,
                                bool is_eval);
 
+  static bool ShouldGenerateLog(Expression* type);
+
   static void SetFunctionInfo(Handle<JSFunction> fun,
                               int length,
                               int function_token_position,
@@ -324,6 +326,8 @@ class CodeGenerator: public AstVisitor {
   // Fast support for object equality testing.
   void GenerateObjectEquals(ZoneList<Expression*>* args);
 
+  void GenerateLog(ZoneList<Expression*>* args);
+
   // Methods and constants for fast case switch statement support.
   //
   // Only allow fast-case switch if the range of labels is at most
index db269a0e32fd5dcef414fa06e463bdf06dc5bb1e..17e4a8d74125633df755e401c3c9f85bfe5bed0e 100644 (file)
@@ -2900,6 +2900,25 @@ void CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) {
 }
 
 
+void CodeGenerator::GenerateLog(ZoneList<Expression*>* args) {
+  // Conditionally generate a log call.
+  // Args:
+  //   0 (literal string): The type of logging (corresponds to the flags).
+  //     This is used to determine whether or not to generate the log call.
+  //   1 (string): Format string.  Access the string at argument index 2
+  //     with '%2s' (see Logger::LogRuntime for all the formats).
+  //   2 (array): Arguments to the format string.
+  ASSERT_EQ(args->length(), 3);
+  if (ShouldGenerateLog(args->at(0))) {
+    Load(args->at(1));
+    Load(args->at(2));
+    __ CallRuntime(Runtime::kLog, 2);
+  }
+  // Finally, we're expected to leave a value on the top of the stack.
+  frame_->Push(Immediate(Factory::undefined_value()));
+}
+
+
 void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) {
   ASSERT(args->length() == 1);
   Load(args->at(0));
index 3289fa58e3f2410208829ecde47e3afcd49620cb..ee1cfc1178d8243fccc5903634b4baf417e5a001 100644 (file)
@@ -201,6 +201,8 @@ class CodeGenerator: public AstVisitor {
                                Handle<Script> script,
                                bool is_eval);
 
+  static bool ShouldGenerateLog(Expression* type);
+
   static void SetFunctionInfo(Handle<JSFunction> fun,
                               int length,
                               int function_token_position,
@@ -348,6 +350,8 @@ class CodeGenerator: public AstVisitor {
   // Fast support for object equality testing.
   void GenerateObjectEquals(ZoneList<Expression*>* args);
 
+  void GenerateLog(ZoneList<Expression*>* args);
+
 
   // Methods and constants for fast case switch statement support.
   //
index f340c0c2f6b13c92c1932c0ee33e4b3ad5bbb68e..265f6badb2e5bd0675ff6a3a5a735050162c491d 100644 (file)
@@ -163,6 +163,19 @@ Handle<Code> CodeGenerator::MakeCode(FunctionLiteral* flit,
 }
 
 
+bool CodeGenerator::ShouldGenerateLog(Expression* type) {
+  ASSERT(type != NULL);
+  if (!Logger::is_enabled()) return false;
+  Handle<String> name = Handle<String>::cast(type->AsLiteral()->handle());
+  if (FLAG_log_regexp) {
+    static Vector<const char> kRegexp = CStrVector("regexp");
+    if (name->IsEqualTo(kRegexp))
+      return true;
+  }
+  return false;
+}
+
+
 // Sets the function info on a function.
 // The start_position points to the first '(' character after the function name
 // in the full script source. When counting characters in the script source the
@@ -338,7 +351,9 @@ bool CodeGenerator::CheckForInlineRuntimeCall(CallRuntime* node) {
     {&v8::internal::CodeGenerator::GenerateFastCharCodeAt,
      "_FastCharCodeAt"},
     {&v8::internal::CodeGenerator::GenerateObjectEquals,
-     "_ObjectEquals"}
+     "_ObjectEquals"},
+    {&v8::internal::CodeGenerator::GenerateLog,
+     "_Log"}
   };
   Handle<String> name = node->name();
   StringShape shape(*name);
index 6b563fee4cd2ea027d26fc9867f2b5c9b8e67a89..6cca7fc35c35a91e7f1fdd209a8297402d86b8e0 100644 (file)
@@ -373,7 +373,6 @@ Handle<Object> RegExpImpl::AtomExec(Handle<JSRegExp> re,
     return Handle<Smi>(Smi::FromInt(-1));
   }
 
-  LOG(RegExpExecEvent(re, start_index, subject));
   int value = Runtime::StringMatch(subject, needle, start_index);
   if (value == -1) return Factory::null_value();
 
@@ -393,7 +392,6 @@ Handle<Object> RegExpImpl::AtomExecGlobal(Handle<JSRegExp> re,
   int subject_length = subject->length();
   int needle_length = needle->length();
   while (true) {
-    LOG(RegExpExecEvent(re, index, subject));
     int value = -1;
     if (index + needle_length <= subject_length) {
       value = Runtime::StringMatch(subject, needle, index);
@@ -575,8 +573,6 @@ Handle<Object> RegExpImpl::JscreExecOnce(Handle<JSRegExp> regexp,
         reinterpret_cast<v8::jscre::JscreRegExp*>(
             internal->GetDataStartAddress());
 
-    LOG(RegExpExecEvent(regexp, previous_index, subject));
-
     rc = v8::jscre::jsRegExpExecute(js_regexp,
                                     two_byte_subject,
                                     subject->length(),
@@ -791,7 +787,6 @@ Handle<Object> RegExpImpl::IrregexpExec(Handle<JSRegExp> regexp,
     PrintF("\n\nSubject string: '%s'\n\n", *(subject->ToCString()));
   }
 #endif
-  LOG(RegExpExecEvent(regexp, previous_index, subject));
 
   if (!subject->IsFlat(StringShape(*subject))) {
     FlattenString(subject);
@@ -845,7 +840,6 @@ Handle<Object> RegExpImpl::IrregexpExecGlobal(Handle<JSRegExp> regexp,
         PrintF("\n\nSubject string: '%s'\n\n", *(subject->ToCString()));
       }
 #endif
-      LOG(RegExpExecEvent(regexp, previous_index, subject));
       matches = IrregexpExecOnce(irregexp,
                                  IrregexpNumberOfCaptures(irregexp),
                                  subject,
index fbefec98292254e2d69d32b87a5faa93e5216681..7ecf2ac63b107e822b72cdacc0597b7f1345bf38 100644 (file)
@@ -350,11 +350,19 @@ void Logger::SharedLibraryEvent(const wchar_t* library_path,
 
 
 #ifdef ENABLE_LOGGING_AND_PROFILING
-void Logger::LogString(Handle<String> str) {
+void Logger::LogString(Handle<String> str, bool show_impl_info) {
   StringShape shape(*str);
   int len = str->length(shape);
-  if (len > 256)
-    len = 256;
+  if (len > 0x1000)
+    len = 0x1000;
+  if (show_impl_info) {
+    fputc(shape.IsAsciiRepresentation() ? 'a' : '2', logfile_);
+    if (shape.IsExternal())
+      fputc('e', logfile_);
+    if (shape.IsSymbol())
+      fputc('#', logfile_);
+    fprintf(logfile_, ":%i:", str->length());
+  }
   for (int i = 0; i < len; i++) {
     uc32 c = str->Get(shape, i);
     if (c > 0xff) {
@@ -389,7 +397,7 @@ void Logger::LogRegExpSource(Handle<JSRegExp> regexp) {
       break;
   }
   fprintf(logfile_, "/");
-  LogString(Handle<String>::cast(source));
+  LogString(Handle<String>::cast(source), false);
   fprintf(logfile_, "/");
 
   // global flag
@@ -423,19 +431,40 @@ void Logger::RegExpCompileEvent(Handle<JSRegExp> regexp, bool in_cache) {
 }
 
 
-void Logger::RegExpExecEvent(Handle<JSRegExp> regexp,
-                             int start_index,
-                             Handle<String> input_string) {
-#ifdef ENABLE_LOGGING_AND_PROFILING
-  if (logfile_ == NULL || !FLAG_log_regexp) return;
+void Logger::LogRuntime(Vector<const char> format, JSArray* args) {
   ScopedLock sl(mutex_);
-
-  fprintf(logfile_, "regexp-run,");
-  LogRegExpSource(regexp);
-  fprintf(logfile_, ",");
-  LogString(input_string);
-  fprintf(logfile_, ",%d..%d\n", start_index, input_string->length());
-#endif
+  HandleScope scope;
+  for (int i = 0; i < format.length(); i++) {
+    char c = format[i];
+    if (c == '%' && i <= format.length() - 2) {
+      i++;
+      ASSERT('0' <= format[i] && format[i] <= '9');
+      Object* obj = args->GetElement(format[i] - '0');
+      i++;
+      switch (format[i]) {
+        case 's':
+          Logger::LogString(Handle<String>(String::cast(obj)), false);
+          break;
+        case 'S':
+          Logger::LogString(Handle<String>(String::cast(obj)), true);
+          break;
+        case 'r':
+          Logger::LogRegExpSource(Handle<JSRegExp>(JSRegExp::cast(obj)));
+          break;
+        case 'x':
+          fprintf(logfile_, "0x%x", Smi::cast(obj)->value());
+          break;
+        case 'i':
+          fprintf(logfile_, "%i", Smi::cast(obj)->value());
+          break;
+        default:
+          UNREACHABLE();
+      }
+    } else {
+      fputc(c, logfile_);
+    }
+  }
+  fputc('\n', logfile_);
 }
 
 
index 62571733f92b7bb2af13143b75cd6e2cf264df23..93ac6a012ad4bb5b427f0c55cc65cff22e574970 100644 (file)
--- a/src/log.h
+++ b/src/log.h
@@ -72,7 +72,11 @@ class SlidingStateWindow;
 
 #undef LOG
 #ifdef ENABLE_LOGGING_AND_PROFILING
-#define LOG(Call) v8::internal::Logger::Call
+#define LOG(Call)                           \
+  do {                                      \
+    if (v8::internal::Logger::is_enabled()) \
+      v8::internal::Logger::Call;           \
+  } while (false)
 #else
 #define LOG(Call) ((void) 0)
 #endif
@@ -189,9 +193,8 @@ class Logger {
 
   static void RegExpCompileEvent(Handle<JSRegExp> regexp, bool in_cache);
 
-  static void RegExpExecEvent(Handle<JSRegExp> regexp,
-                              int start_index,
-                              Handle<String> input_string);
+  // Log an event reported from generated code
+  static void LogRuntime(Vector<const char> format, JSArray* args);
 
 #ifdef ENABLE_LOGGING_AND_PROFILING
   static StateTag state() {
@@ -199,13 +202,15 @@ class Logger {
   }
 #endif
 
+  static bool is_enabled() { return logfile_ != NULL; }
+
 #ifdef ENABLE_LOGGING_AND_PROFILING
  private:
 
   // Emits the source code of a regexp. Used by regexp events.
   static void LogRegExpSource(Handle<JSRegExp> regexp);
 
-  static void LogString(Handle<String> str);
+  static void LogString(Handle<String> str, bool show_impl_info);
 
   // Emits a profiler tick event. Used by the profiler thread.
   static void TickEvent(TickSample* sample, bool overflow);
index 4baa9cd052a15efd247cffebd0450daed66a07ee..4b0d5370479aa7de3c3cffe11d03b71ffa8af52f 100644 (file)
@@ -178,6 +178,7 @@ function RegExpExec(string) {
     return null;
   }
 
+  %_Log('regexp', 'regexp-exec,%0r,%1S,%2i', [this, s, lastIndex]);
   // matchIndices is an array of integers with length of captures*2,
   // each pair of integers specified the start and the end of index
   // in the string.
index e796081008c417f7e58632808d854e53cf269e7e..931c2a03e5a960384ce733727a599236d8422cc8 100644 (file)
@@ -5840,6 +5840,16 @@ static Object* Runtime_ListNatives(Arguments args) {
 #endif
 
 
+static Object* Runtime_Log(Arguments args) {
+  ASSERT(args.length() == 2);
+  String* format = String::cast(args[0]);
+  Vector<const char> chars = format->ToAsciiVector();
+  JSArray* elms = JSArray::cast(args[1]);
+  Logger::LogRuntime(chars, elms);
+  return Heap::undefined_value();
+}
+
+
 static Object* Runtime_IS_VAR(Arguments args) {
   UNREACHABLE();  // implemented as macro in the parser
   return NULL;
index baff9f9ee9d0489a1c78768220e976600a995f34..cb8d40b0c2d87e35b2d317ef704bbef0fbd613bd 100644 (file)
@@ -285,6 +285,8 @@ namespace v8 { namespace internal {
   F(DebugBreak, 0) \
   F(FunctionGetAssemblerCode, 1) \
   F(Abort, 2) \
+  /* Logging */ \
+  F(Log, 2) \
   \
   /* Pseudo functions - handled as macros by parser */ \
   F(IS_VAR, 1)
index 78606a60e97dd17c31edb45a2f167ac0cccb2fb3..614d541c57225697eb560c0209676d9299459c70 100644 (file)
@@ -152,6 +152,7 @@ function StringMatch(regexp) {
   var subject = ToString(this);
 
   if (!regexp.global) return regexp.exec(subject);
+  %_Log('regexp', 'regexp-match,%0S,%1r', [subject, regexp]);
   var matches = DoRegExpExecGlobal(regexp, subject);
 
   // If the regexp did not match, return null.
@@ -185,6 +186,7 @@ function StringReplace(search, replace) {
 
   // Delegate to one of the regular expression variants if necessary.
   if (IS_REGEXP(search)) {
+    %_Log('regexp', 'regexp-replace,%0r,%1S', [search, subject]);
     if (IS_FUNCTION(replace)) {
       return StringReplaceRegExpWithFunction(subject, search, replace);
     } else {
@@ -513,7 +515,13 @@ function StringSplit(separator, limit) {
   var currentIndex = 0;
   var startIndex = 0;
 
-  var sep = IS_REGEXP(separator) ? separator : ToString(separator);
+  var sep;
+  if (IS_REGEXP(separator)) {
+    sep = separator;
+    %_Log('regexp', 'regexp-split,%0S,%1r', [subject, sep]);
+  } else {
+    sep = ToString(separator);
+  }
 
   if (length === 0) {
     if (splitMatch(sep, subject, 0, 0) != null) return result;
index 5b5d6d9a2ddf415886390ef55797412128c212f6..a2c3217110bff4240a4e4e479060bbb30226bd1d 100644 (file)
@@ -123,7 +123,8 @@ var knownProblems = {
   "CreateObjectLiteralBoilerplate": true,
   "CloneObjectLiteralBoilerplate": true,
   "IS_VAR": true,
-  "ResolvePossiblyDirectEval": true
+  "ResolvePossiblyDirectEval": true,
+  "Log": true
 };
 
 var currentlyUncallable = {