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
This commit is contained in:
lrn@chromium.org 2008-09-11 11:24:45 +00:00
parent b5a72a1645
commit c5d98b775d
7 changed files with 115 additions and 19 deletions

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

View 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;
}

View File

@ -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);

View 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>",

View 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);
}

View 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();

View File

@ -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<typename T>
class SmartPointer {
public:
// Default constructor. Construct an empty scoped pointer.
inline SmartPointer() : p(NULL) {}
// Construct a scoped pointer from a plain one.
inline SmartPointer(T* pointer) : p(pointer) {}
// 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); }
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;
}