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:
parent
b5a72a1645
commit
c5d98b775d
@ -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,
|
||||
|
74
src/log.cc
74
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<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;
|
||||
}
|
||||
|
||||
|
13
src/log.h
13
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);
|
||||
|
||||
|
@ -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>",
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user