Commit c5d98b77 authored by lrn@chromium.org's avatar lrn@chromium.org

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
parent b5a72a16
...@@ -205,6 +205,8 @@ Handle<Object> RegExpImpl::JsreCompile(Handle<JSValue> re, ...@@ -205,6 +205,8 @@ Handle<Object> RegExpImpl::JsreCompile(Handle<JSValue> re,
value->set(INTERNAL_INDEX, *internal); value->set(INTERNAL_INDEX, *internal);
re->set_value(*value); re->set_value(*value);
LOG(RegExpCompileEvent(re));
return re; return re;
} }
...@@ -223,6 +225,8 @@ Handle<Object> RegExpImpl::JsreExecOnce(Handle<JSValue> regexp, ...@@ -223,6 +225,8 @@ Handle<Object> RegExpImpl::JsreExecOnce(Handle<JSValue> regexp,
const JSRegExp* js_regexp = const JSRegExp* js_regexp =
reinterpret_cast<JSRegExp*>(internal->GetDataStartAddress()); reinterpret_cast<JSRegExp*>(internal->GetDataStartAddress());
LOG(RegExpExecEvent(regexp, previous_index, subject));
rc = jsRegExpExecute(js_regexp, two_byte_subject, rc = jsRegExpExecute(js_regexp, two_byte_subject,
subject->length(), subject->length(),
previous_index, previous_index,
......
...@@ -52,6 +52,8 @@ DEFINE_bool(log_state_changes, false, "Log state changes."); ...@@ -52,6 +52,8 @@ DEFINE_bool(log_state_changes, false, "Log state changes.");
DEFINE_bool(log_suspect, false, "Log suspect operations."); DEFINE_bool(log_suspect, false, "Log suspect operations.");
DEFINE_bool(prof, false, DEFINE_bool(prof, false,
"Log statistical profiling information (implies --log-code)."); "Log statistical profiling information (implies --log-code).");
DEFINE_bool(log_regexp, false,
"Log regular expression execution.");
DEFINE_bool(sliding_state_window, false, DEFINE_bool(sliding_state_window, false,
"Update sliding state window counters."); "Update sliding state window counters.");
...@@ -368,6 +370,75 @@ void Logger::SharedLibraryEvent(const wchar_t* library_path, ...@@ -368,6 +370,75 @@ void Logger::SharedLibraryEvent(const wchar_t* library_path,
#endif #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) { void Logger::ApiIndexedSecurityCheck(uint32_t index) {
#ifdef ENABLE_LOGGING_AND_PROFILING #ifdef ENABLE_LOGGING_AND_PROFILING
if (logfile_ == NULL || !FLAG_log_api) return; if (logfile_ == NULL || !FLAG_log_api) return;
...@@ -612,6 +683,7 @@ bool Logger::Setup() { ...@@ -612,6 +683,7 @@ bool Logger::Setup() {
FLAG_log_gc = true; FLAG_log_gc = true;
FLAG_log_suspect = true; FLAG_log_suspect = true;
FLAG_log_handles = true; FLAG_log_handles = true;
FLAG_log_regexp = true;
} }
// --prof implies --log-code. // --prof implies --log-code.
...@@ -620,7 +692,7 @@ bool Logger::Setup() { ...@@ -620,7 +692,7 @@ bool Logger::Setup() {
// Each of the individual log flags implies --log. Check after // Each of the individual log flags implies --log. Check after
// checking --log-all and --prof in case they set --log-code. // checking --log-all and --prof in case they set --log-code.
if (FLAG_log_api || FLAG_log_code || FLAG_log_gc || 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; FLAG_log = true;
} }
......
...@@ -174,6 +174,15 @@ class Logger { ...@@ -174,6 +174,15 @@ class Logger {
unsigned start, unsigned start,
unsigned end); 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 #ifdef ENABLE_LOGGING_AND_PROFILING
static StateTag state() { static StateTag state() {
return current_state_ ? current_state_->state() : OTHER; return current_state_ ? current_state_->state() : OTHER;
...@@ -182,6 +191,10 @@ class Logger { ...@@ -182,6 +191,10 @@ class Logger {
#ifdef ENABLE_LOGGING_AND_PROFILING #ifdef ENABLE_LOGGING_AND_PROFILING
private: 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. // Emits a profiler tick event. Used by the profiler thread.
static void TickEvent(TickSample* sample, bool overflow); static void TickEvent(TickSample* sample, bool overflow);
......
...@@ -46,7 +46,7 @@ void MessageHandler::DefaultMessageReport(const MessageLocation* loc, ...@@ -46,7 +46,7 @@ void MessageHandler::DefaultMessageReport(const MessageLocation* loc,
} else { } else {
HandleScope scope; HandleScope scope;
Handle<Object> data(loc->script()->name()); Handle<Object> data(loc->script()->name());
SmartPointer<char> data_str = NULL; SmartPointer<char> data_str;
if (data->IsString()) if (data->IsString())
data_str = Handle<String>::cast(data)->ToCString(DISALLOW_NULLS); data_str = Handle<String>::cast(data)->ToCString(DISALLOW_NULLS);
PrintF("%s:%i: %s\n", *data_str ? *data_str : "<unknown>", PrintF("%s:%i: %s\n", *data_str ? *data_str : "<unknown>",
......
...@@ -3023,11 +3023,11 @@ const uc16* String::GetTwoByteData(unsigned start) { ...@@ -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()); ASSERT(NativeAllocationChecker::allocation_allowed());
if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) { if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
return NULL; return SmartPointer<uc16>();
} }
Access<StringInputBuffer> buffer(&string_input_buffer); Access<StringInputBuffer> buffer(&string_input_buffer);
...@@ -3041,7 +3041,7 @@ uc16* String::ToWideCString(RobustnessFlag robust_flag) { ...@@ -3041,7 +3041,7 @@ uc16* String::ToWideCString(RobustnessFlag robust_flag) {
result[i++] = character; result[i++] = character;
} }
result[i] = 0; result[i] = 0;
return result; return SmartPointer<uc16>(result);
} }
......
...@@ -2861,7 +2861,7 @@ class String: public HeapObject { ...@@ -2861,7 +2861,7 @@ class String: public HeapObject {
// ROBUST_STRING_TRAVERSAL invokes behaviour that is robust This means it // ROBUST_STRING_TRAVERSAL invokes behaviour that is robust This means it
// handles unexpected data without causing assert failures and it does not // handles unexpected data without causing assert failures and it does not
// do any heap allocations. This is useful when printing stack traces. // 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. // Tells whether the hash code has been computed.
inline bool HasHashCode(); inline bool HasHashCode();
......
...@@ -31,19 +31,18 @@ ...@@ -31,19 +31,18 @@
namespace v8 { namespace internal { 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. // destructor is called.
template<typename T> template<typename T>
class SmartPointer { class SmartPointer {
public: 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 // Construct a scoped pointer from a plain one.
// NewArray. explicit inline SmartPointer(T* pointer) : p(pointer) {}
inline ~SmartPointer() { if (p) DeleteArray(p); }
// Copy constructor removes the pointer from the original to avoid double // Copy constructor removes the pointer from the original to avoid double
...@@ -53,13 +52,20 @@ class SmartPointer { ...@@ -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. // You can get the underlying pointer out with the * operator.
inline T* operator*() { return p; } inline T* operator*() { return p; }
// You can use -> as if it was a plain pointer. // You can use [n] to index as if it was a plain pointer
inline T* operator->() { return p; } inline T& operator[](size_t i) {
return p[i];
}
// We don't have implicit conversion to a T* since that hinders migration: // 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 // You would not be able to change a method from returning a T* to
...@@ -81,8 +87,9 @@ class SmartPointer { ...@@ -81,8 +87,9 @@ class SmartPointer {
// double freeing. // double freeing.
inline SmartPointer& operator=(const SmartPointer<T>& rhs) { inline SmartPointer& operator=(const SmartPointer<T>& rhs) {
ASSERT(p == NULL); ASSERT(p == NULL);
p = rhs.p; T* tmp = rhs.p; // swap to handle self-assignment
const_cast<SmartPointer<T>&>(rhs).p = NULL; const_cast<SmartPointer<T>&>(rhs).p = NULL;
p = tmp;
return *this; return *this;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment