value->set(INTERNAL_INDEX, *internal);
re->set_value(*value);
+ LOG(RegExpCompileEvent(re));
+
return re;
}
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,
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.");
#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;
FLAG_log_gc = true;
FLAG_log_suspect = true;
FLAG_log_handles = true;
+ FLAG_log_regexp = true;
}
// --prof implies --log-code.
// 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;
}
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;
#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);
} 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>",
}
-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);
result[i++] = character;
}
result[i] = 0;
- return result;
+ return SmartPointer<uc16>(result);
}
// 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();
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
}
+ // 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
// 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;
}