- Added caching of regexp data in the compilation cache.

- Changed the structure of regexp objects from having two internal
  fields to having a single field containing a fixed array, since it's
  easier to store the whole fixed array in the cache.
- Move printing of the command to after printing std{err,out} in the
  compact progress indicators in the test framework.


git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@579 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 5d36cc80
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
namespace v8 { namespace internal { namespace v8 { namespace internal {
enum { enum {
NUMBER_OF_ENTRY_KINDS = CompilationCache::EVAL_CONTEXTUAL + 1 NUMBER_OF_ENTRY_KINDS = CompilationCache::LAST_ENTRY + 1
}; };
...@@ -132,9 +132,9 @@ Handle<JSFunction> CompilationCache::LookupEval(Handle<String> source, ...@@ -132,9 +132,9 @@ Handle<JSFunction> CompilationCache::LookupEval(Handle<String> source,
} }
void CompilationCache::Associate(Handle<String> source, void CompilationCache::PutFunction(Handle<String> source,
Entry entry, Entry entry,
Handle<JSFunction> boilerplate) { Handle<JSFunction> boilerplate) {
HandleScope scope; HandleScope scope;
ASSERT(boilerplate->IsBoilerplate()); ASSERT(boilerplate->IsBoilerplate());
Handle<CompilationCacheTable> table = GetTable(entry); Handle<CompilationCacheTable> table = GetTable(entry);
...@@ -142,6 +142,29 @@ void CompilationCache::Associate(Handle<String> source, ...@@ -142,6 +142,29 @@ void CompilationCache::Associate(Handle<String> source,
} }
Handle<FixedArray> CompilationCache::LookupRegExp(Handle<String> source,
JSRegExp::Flags flags) {
Handle<CompilationCacheTable> table = GetTable(REGEXP);
Object* result = table->LookupRegExp(*source, flags);
if (result->IsFixedArray()) {
Counters::regexp_cache_hits.Increment();
return Handle<FixedArray>(FixedArray::cast(result));
} else {
Counters::regexp_cache_misses.Increment();
return Handle<FixedArray>();
}
}
void CompilationCache::PutRegExp(Handle<String> source,
JSRegExp::Flags flags,
Handle<FixedArray> data) {
HandleScope scope;
Handle<CompilationCacheTable> table = GetTable(REGEXP);
CALL_HEAP_FUNCTION_VOID(table->PutRegExp(*source, flags, *data));
}
void CompilationCache::Clear() { void CompilationCache::Clear() {
for (int i = 0; i < NUMBER_OF_ENTRY_KINDS; i++) { for (int i = 0; i < NUMBER_OF_ENTRY_KINDS; i++) {
tables[i] = Heap::undefined_value(); tables[i] = Heap::undefined_value();
......
...@@ -42,7 +42,9 @@ class CompilationCache { ...@@ -42,7 +42,9 @@ class CompilationCache {
enum Entry { enum Entry {
SCRIPT, SCRIPT,
EVAL_GLOBAL, EVAL_GLOBAL,
EVAL_CONTEXTUAL EVAL_CONTEXTUAL,
REGEXP,
LAST_ENTRY = REGEXP
}; };
// Finds the script function boilerplate for a source // Finds the script function boilerplate for a source
...@@ -59,11 +61,22 @@ class CompilationCache { ...@@ -59,11 +61,22 @@ class CompilationCache {
static Handle<JSFunction> LookupEval(Handle<String> source, static Handle<JSFunction> LookupEval(Handle<String> source,
Entry entry); Entry entry);
// Returns the regexp data associated with the given regexp if it
// is in cache, otherwise an empty handle.
static Handle<FixedArray> LookupRegExp(Handle<String> source,
JSRegExp::Flags flags);
// Associate the (source, flags) pair to the given regexp data.
// This may overwrite an existing mapping.
static void PutRegExp(Handle<String> source,
JSRegExp::Flags flags,
Handle<FixedArray> data);
// Associate the (source, kind) pair to the boilerplate. This may // Associate the (source, kind) pair to the boilerplate. This may
// overwrite an existing mapping. // overwrite an existing mapping.
static void Associate(Handle<String> source, static void PutFunction(Handle<String> source,
Entry entry, Entry entry,
Handle<JSFunction> boilerplate); Handle<JSFunction> boilerplate);
// Clear the cache - also used to initialize the cache at startup. // Clear the cache - also used to initialize the cache at startup.
static void Clear(); static void Clear();
......
...@@ -189,7 +189,7 @@ Handle<JSFunction> Compiler::Compile(Handle<String> source, ...@@ -189,7 +189,7 @@ Handle<JSFunction> Compiler::Compile(Handle<String> source,
// Compile the function and add it to the cache. // Compile the function and add it to the cache.
result = MakeFunction(true, false, script, extension, pre_data); result = MakeFunction(true, false, script, extension, pre_data);
if (extension == NULL && !result.is_null()) { if (extension == NULL && !result.is_null()) {
CompilationCache::Associate(source, CompilationCache::SCRIPT, result); CompilationCache::PutFunction(source, CompilationCache::SCRIPT, result);
} }
// Get rid of the pre-parsing data (if necessary). // Get rid of the pre-parsing data (if necessary).
...@@ -223,7 +223,7 @@ Handle<JSFunction> Compiler::CompileEval(Handle<String> source, ...@@ -223,7 +223,7 @@ Handle<JSFunction> Compiler::CompileEval(Handle<String> source,
script->set_line_offset(Smi::FromInt(line_offset)); script->set_line_offset(Smi::FromInt(line_offset));
result = MakeFunction(is_global, true, script, NULL, NULL); result = MakeFunction(is_global, true, script, NULL, NULL);
if (!result.is_null()) { if (!result.is_null()) {
CompilationCache::Associate(source, entry, result); CompilationCache::PutFunction(source, entry, result);
} }
} }
return result; return result;
......
...@@ -808,6 +808,20 @@ Handle<Map> Factory::ObjectLiteralMapFromCache(Handle<Context> context, ...@@ -808,6 +808,20 @@ Handle<Map> Factory::ObjectLiteralMapFromCache(Handle<Context> context,
} }
void Factory::SetRegExpData(Handle<JSRegExp> regexp,
JSRegExp::Type type,
Handle<String> source,
JSRegExp::Flags flags,
Handle<Object> data) {
Handle<FixedArray> store = NewFixedArray(JSRegExp::kDataSize);
store->set(JSRegExp::kTagIndex, Smi::FromInt(type));
store->set(JSRegExp::kSourceIndex, *source);
store->set(JSRegExp::kFlagsIndex, Smi::FromInt(flags.value()));
store->set(JSRegExp::kAtomPatternIndex, *data);
regexp->set_data(*store);
}
void Factory::ConfigureInstance(Handle<FunctionTemplateInfo> desc, void Factory::ConfigureInstance(Handle<FunctionTemplateInfo> desc,
Handle<JSObject> instance, Handle<JSObject> instance,
bool* pending_exception) { bool* pending_exception) {
......
...@@ -308,6 +308,14 @@ class Factory : public AllStatic { ...@@ -308,6 +308,14 @@ class Factory : public AllStatic {
static Handle<Map> ObjectLiteralMapFromCache(Handle<Context> context, static Handle<Map> ObjectLiteralMapFromCache(Handle<Context> context,
Handle<FixedArray> keys); Handle<FixedArray> keys);
// Creates a new FixedArray that holds the data associated with the
// regexp and stores it in the regexp.
static void SetRegExpData(Handle<JSRegExp> regexp,
JSRegExp::Type type,
Handle<String> source,
JSRegExp::Flags flags,
Handle<Object> data);
private: private:
static Handle<JSFunction> NewFunctionHelper(Handle<String> name, static Handle<JSFunction> NewFunctionHelper(Handle<String> name,
Handle<Object> prototype); Handle<Object> prototype);
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include "platform.h" #include "platform.h"
#include "runtime.h" #include "runtime.h"
#include "top.h" #include "top.h"
#include "compilation-cache.h"
namespace v8 { namespace internal { namespace v8 { namespace internal {
...@@ -143,29 +144,59 @@ Handle<String> RegExpImpl::StringToTwoByte(Handle<String> pattern) { ...@@ -143,29 +144,59 @@ Handle<String> RegExpImpl::StringToTwoByte(Handle<String> pattern) {
} }
static JSRegExp::Flags RegExpFlagsFromString(Handle<String> str) {
int flags = JSRegExp::NONE;
for (int i = 0; i < str->length(); i++) {
switch (str->Get(i)) {
case 'i':
flags |= JSRegExp::IGNORE_CASE;
break;
case 'g':
flags |= JSRegExp::GLOBAL;
break;
case 'm':
flags |= JSRegExp::MULTILINE;
break;
}
}
return JSRegExp::Flags(flags);
}
unibrow::Predicate<unibrow::RegExpSpecialChar, 128> is_reg_exp_special_char; unibrow::Predicate<unibrow::RegExpSpecialChar, 128> is_reg_exp_special_char;
Handle<Object> RegExpImpl::Compile(Handle<JSRegExp> re, Handle<Object> RegExpImpl::Compile(Handle<JSRegExp> re,
Handle<String> pattern, Handle<String> pattern,
Handle<String> flags) { Handle<String> flag_str) {
bool is_atom = true; JSRegExp::Flags flags = RegExpFlagsFromString(flag_str);
for (int i = 0; is_atom && i < flags->length(); i++) { Handle<FixedArray> cached = CompilationCache::LookupRegExp(pattern, flags);
if (flags->Get(i) == 'i') bool in_cache = !cached.is_null();
is_atom = false;
}
for (int i = 0; is_atom && i < pattern->length(); i++) {
if (is_reg_exp_special_char.get(pattern->Get(i)))
is_atom = false;
}
Handle<Object> result; Handle<Object> result;
if (is_atom) { if (in_cache) {
result = AtomCompile(re, pattern); re->set_data(*cached);
result = re;
} else { } else {
result = JsreCompile(re, pattern, flags); bool is_atom = !flags.is_ignore_case();
for (int i = 0; is_atom && i < pattern->length(); i++) {
if (is_reg_exp_special_char.get(pattern->Get(i)))
is_atom = false;
}
if (is_atom) {
result = AtomCompile(re, pattern, flags);
} else {
result = JsreCompile(re, pattern, flags);
}
Object* data = re->data();
if (data->IsFixedArray()) {
// If compilation succeeded then the data is set on the regexp
// and we can store it in the cache.
Handle<FixedArray> data(FixedArray::cast(re->data()));
CompilationCache::PutRegExp(pattern, flags, data);
}
} }
LOG(RegExpCompileEvent(re)); LOG(RegExpCompileEvent(re, in_cache));
return result; return result;
} }
...@@ -173,7 +204,7 @@ Handle<Object> RegExpImpl::Compile(Handle<JSRegExp> re, ...@@ -173,7 +204,7 @@ Handle<Object> RegExpImpl::Compile(Handle<JSRegExp> re,
Handle<Object> RegExpImpl::Exec(Handle<JSRegExp> regexp, Handle<Object> RegExpImpl::Exec(Handle<JSRegExp> regexp,
Handle<String> subject, Handle<String> subject,
Handle<Object> index) { Handle<Object> index) {
switch (regexp->type_tag()) { switch (regexp->TypeTag()) {
case JSRegExp::JSCRE: case JSRegExp::JSCRE:
return JsreExec(regexp, subject, index); return JsreExec(regexp, subject, index);
case JSRegExp::ATOM: case JSRegExp::ATOM:
...@@ -187,7 +218,7 @@ Handle<Object> RegExpImpl::Exec(Handle<JSRegExp> regexp, ...@@ -187,7 +218,7 @@ Handle<Object> RegExpImpl::Exec(Handle<JSRegExp> regexp,
Handle<Object> RegExpImpl::ExecGlobal(Handle<JSRegExp> regexp, Handle<Object> RegExpImpl::ExecGlobal(Handle<JSRegExp> regexp,
Handle<String> subject) { Handle<String> subject) {
switch (regexp->type_tag()) { switch (regexp->TypeTag()) {
case JSRegExp::JSCRE: case JSRegExp::JSCRE:
return JsreExecGlobal(regexp, subject); return JsreExecGlobal(regexp, subject);
case JSRegExp::ATOM: case JSRegExp::ATOM:
...@@ -200,9 +231,9 @@ Handle<Object> RegExpImpl::ExecGlobal(Handle<JSRegExp> regexp, ...@@ -200,9 +231,9 @@ Handle<Object> RegExpImpl::ExecGlobal(Handle<JSRegExp> regexp,
Handle<Object> RegExpImpl::AtomCompile(Handle<JSRegExp> re, Handle<Object> RegExpImpl::AtomCompile(Handle<JSRegExp> re,
Handle<String> pattern) { Handle<String> pattern,
re->set_type_tag(JSRegExp::ATOM); JSRegExp::Flags flags) {
re->set_data(*pattern); Factory::SetRegExpData(re, JSRegExp::ATOM, pattern, flags, pattern);
return re; return re;
} }
...@@ -210,7 +241,7 @@ Handle<Object> RegExpImpl::AtomCompile(Handle<JSRegExp> re, ...@@ -210,7 +241,7 @@ Handle<Object> RegExpImpl::AtomCompile(Handle<JSRegExp> re,
Handle<Object> RegExpImpl::AtomExec(Handle<JSRegExp> re, Handle<Object> RegExpImpl::AtomExec(Handle<JSRegExp> re,
Handle<String> subject, Handle<String> subject,
Handle<Object> index) { Handle<Object> index) {
Handle<String> needle(String::cast(re->data())); Handle<String> needle(String::cast(re->DataAt(JSRegExp::kAtomPatternIndex)));
uint32_t start_index; uint32_t start_index;
if (!Array::IndexFromObject(*index, &start_index)) { if (!Array::IndexFromObject(*index, &start_index)) {
...@@ -234,7 +265,7 @@ Handle<Object> RegExpImpl::AtomExec(Handle<JSRegExp> re, ...@@ -234,7 +265,7 @@ Handle<Object> RegExpImpl::AtomExec(Handle<JSRegExp> re,
Handle<Object> RegExpImpl::AtomExecGlobal(Handle<JSRegExp> re, Handle<Object> RegExpImpl::AtomExecGlobal(Handle<JSRegExp> re,
Handle<String> subject) { Handle<String> subject) {
Handle<String> needle(String::cast(re->data())); Handle<String> needle(String::cast(re->DataAt(JSRegExp::kAtomPatternIndex)));
Handle<JSArray> result = Factory::NewJSArray(1); Handle<JSArray> result = Factory::NewJSArray(1);
int index = 0; int index = 0;
int match_count = 0; int match_count = 0;
...@@ -269,14 +300,13 @@ Handle<Object> RegExpImpl::AtomExecGlobal(Handle<JSRegExp> re, ...@@ -269,14 +300,13 @@ Handle<Object> RegExpImpl::AtomExecGlobal(Handle<JSRegExp> re,
Handle<Object> RegExpImpl::JsreCompile(Handle<JSRegExp> re, Handle<Object> RegExpImpl::JsreCompile(Handle<JSRegExp> re,
Handle<String> pattern, Handle<String> pattern,
Handle<String> flags) { JSRegExp::Flags flags) {
JSRegExpIgnoreCaseOption case_option = JSRegExpDoNotIgnoreCase; JSRegExpIgnoreCaseOption case_option = flags.is_ignore_case()
JSRegExpMultilineOption multiline_option = JSRegExpSingleLine; ? JSRegExpIgnoreCase
FlattenString(flags); : JSRegExpDoNotIgnoreCase;
for (int i = 0; i < flags->length(); i++) { JSRegExpMultilineOption multiline_option = flags.is_multiline()
if (flags->Get(i) == 'i') case_option = JSRegExpIgnoreCase; ? JSRegExpMultiline
if (flags->Get(i) == 'm') multiline_option = JSRegExpMultiline; : JSRegExpSingleLine;
}
Handle<String> two_byte_pattern = StringToTwoByte(pattern); Handle<String> two_byte_pattern = StringToTwoByte(pattern);
...@@ -328,8 +358,7 @@ Handle<Object> RegExpImpl::JsreCompile(Handle<JSRegExp> re, ...@@ -328,8 +358,7 @@ Handle<Object> RegExpImpl::JsreCompile(Handle<JSRegExp> re,
Handle<FixedArray> value = Factory::NewFixedArray(2); Handle<FixedArray> value = Factory::NewFixedArray(2);
value->set(CAPTURE_INDEX, Smi::FromInt(number_of_captures)); value->set(CAPTURE_INDEX, Smi::FromInt(number_of_captures));
value->set(INTERNAL_INDEX, *internal); value->set(INTERNAL_INDEX, *internal);
re->set_type_tag(JSRegExp::JSCRE); Factory::SetRegExpData(re, JSRegExp::JSCRE, pattern, flags, value);
re->set_data(*value);
return re; return re;
} }
...@@ -499,16 +528,14 @@ Handle<Object> RegExpImpl::JsreExecGlobal(Handle<JSRegExp> regexp, ...@@ -499,16 +528,14 @@ Handle<Object> RegExpImpl::JsreExecGlobal(Handle<JSRegExp> regexp,
int RegExpImpl::JsreCapture(Handle<JSRegExp> re) { int RegExpImpl::JsreCapture(Handle<JSRegExp> re) {
Object* value = re->data(); FixedArray* value = FixedArray::cast(re->DataAt(JSRegExp::kJscreDataIndex));
ASSERT(value->IsFixedArray()); return Smi::cast(value->get(CAPTURE_INDEX))->value();
return Smi::cast(FixedArray::cast(value)->get(CAPTURE_INDEX))->value();
} }
ByteArray* RegExpImpl::JsreInternal(Handle<JSRegExp> re) { ByteArray* RegExpImpl::JsreInternal(Handle<JSRegExp> re) {
Object* value = re->data(); FixedArray* value = FixedArray::cast(re->DataAt(JSRegExp::kJscreDataIndex));
ASSERT(value->IsFixedArray()); return ByteArray::cast(value->get(INTERNAL_INDEX));
return ByteArray::cast(FixedArray::cast(value)->get(INTERNAL_INDEX));
} }
}} // namespace v8::internal }} // namespace v8::internal
...@@ -62,7 +62,8 @@ class RegExpImpl { ...@@ -62,7 +62,8 @@ class RegExpImpl {
Handle<String> subject); Handle<String> subject);
static Handle<Object> AtomCompile(Handle<JSRegExp> re, static Handle<Object> AtomCompile(Handle<JSRegExp> re,
Handle<String> pattern); Handle<String> pattern,
JSRegExp::Flags flags);
static Handle<Object> AtomExec(Handle<JSRegExp> regexp, static Handle<Object> AtomExec(Handle<JSRegExp> regexp,
Handle<String> subject, Handle<String> subject,
...@@ -73,7 +74,7 @@ class RegExpImpl { ...@@ -73,7 +74,7 @@ class RegExpImpl {
static Handle<Object> JsreCompile(Handle<JSRegExp> re, static Handle<Object> JsreCompile(Handle<JSRegExp> re,
Handle<String> pattern, Handle<String> pattern,
Handle<String> flags); JSRegExp::Flags flags);
static Handle<Object> JsreExec(Handle<JSRegExp> regexp, static Handle<Object> JsreExec(Handle<JSRegExp> regexp,
Handle<String> subject, Handle<String> subject,
......
...@@ -377,14 +377,12 @@ void Logger::LogRegExpSource(Handle<JSRegExp> regexp) { ...@@ -377,14 +377,12 @@ void Logger::LogRegExpSource(Handle<JSRegExp> regexp) {
return; return;
} }
if (regexp->type()->IsSmi()) { switch (regexp->TypeTag()) {
switch (regexp->type_tag()) {
case JSRegExp::ATOM: case JSRegExp::ATOM:
fprintf(logfile_, "a"); fprintf(logfile_, "a");
break; break;
default: default:
break; break;
}
} }
fprintf(logfile_, "/"); fprintf(logfile_, "/");
LogString(Handle<String>::cast(source)); LogString(Handle<String>::cast(source));
...@@ -409,14 +407,14 @@ void Logger::LogRegExpSource(Handle<JSRegExp> regexp) { ...@@ -409,14 +407,14 @@ void Logger::LogRegExpSource(Handle<JSRegExp> regexp) {
#endif // ENABLE_LOGGING_AND_PROFILING #endif // ENABLE_LOGGING_AND_PROFILING
void Logger::RegExpCompileEvent(Handle<JSRegExp> regexp) { void Logger::RegExpCompileEvent(Handle<JSRegExp> regexp, bool in_cache) {
#ifdef ENABLE_LOGGING_AND_PROFILING #ifdef ENABLE_LOGGING_AND_PROFILING
if (logfile_ == NULL || !FLAG_log_regexp) return; if (logfile_ == NULL || !FLAG_log_regexp) return;
ScopedLock sl(mutex_); ScopedLock sl(mutex_);
fprintf(logfile_, "regexp-compile,"); fprintf(logfile_, "regexp-compile,");
LogRegExpSource(regexp); LogRegExpSource(regexp);
fprintf(logfile_, "\n"); fprintf(logfile_, in_cache ? ",hit\n" : ",miss\n");
#endif #endif
} }
......
...@@ -181,7 +181,7 @@ class Logger { ...@@ -181,7 +181,7 @@ class Logger {
// ==== Events logged by --log-regexp ==== // ==== Events logged by --log-regexp ====
// Regexp compilation and execution events. // Regexp compilation and execution events.
static void RegExpCompileEvent(Handle<JSRegExp> regexp); static void RegExpCompileEvent(Handle<JSRegExp> regexp, bool in_cache);
static void RegExpExecEvent(Handle<JSRegExp> regexp, static void RegExpExecEvent(Handle<JSRegExp> regexp,
int start_index, int start_index,
......
...@@ -660,19 +660,22 @@ void JSArray::JSArrayVerify() { ...@@ -660,19 +660,22 @@ void JSArray::JSArrayVerify() {
void JSRegExp::JSRegExpVerify() { void JSRegExp::JSRegExpVerify() {
JSObjectVerify(); JSObjectVerify();
ASSERT(type()->IsSmi() || type()->IsUndefined()); ASSERT(data()->IsUndefined() || data()->IsFixedArray());
if (type()->IsSmi()) { switch (TypeTag()) {
switch (type_tag()) { case JSRegExp::ATOM: {
case JSRegExp::JSCRE: FixedArray* arr = FixedArray::cast(data());
ASSERT(data()->IsFixedArray()); ASSERT(arr->get(JSRegExp::kAtomPatternIndex)->IsString());
break; break;
default:
ASSERT_EQ(JSRegExp::ATOM, type_tag());
ASSERT(data()->IsString());
break;
} }
} else { case JSRegExp::JSCRE: {
ASSERT(data()->IsUndefined()); FixedArray* arr = FixedArray::cast(data());
ASSERT(arr->get(JSRegExp::kJscreDataIndex)->IsFixedArray());
break;
}
default:
ASSERT_EQ(JSRegExp::NOT_COMPILED, TypeTag());
ASSERT(data()->IsUndefined());
break;
} }
} }
......
...@@ -2166,16 +2166,19 @@ ACCESSORS(JSArray, length, Object, kLengthOffset) ...@@ -2166,16 +2166,19 @@ ACCESSORS(JSArray, length, Object, kLengthOffset)
ACCESSORS(JSRegExp, data, Object, kDataOffset) ACCESSORS(JSRegExp, data, Object, kDataOffset)
ACCESSORS(JSRegExp, type, Object, kTypeOffset)
JSRegExp::Type JSRegExp::type_tag() { JSRegExp::Type JSRegExp::TypeTag() {
return static_cast<JSRegExp::Type>(Smi::cast(type())->value()); Object* data = this->data();
if (data->IsUndefined()) return JSRegExp::NOT_COMPILED;
Smi* smi = Smi::cast(FixedArray::cast(data)->get(kTagIndex));
return static_cast<JSRegExp::Type>(smi->value());
} }
void JSRegExp::set_type_tag(JSRegExp::Type value) { Object* JSRegExp::DataAt(int index) {
set_type(Smi::FromInt(value)); ASSERT(TypeTag() != NOT_COMPILED);
return FixedArray::cast(data())->get(index);
} }
......
...@@ -5551,6 +5551,46 @@ class StringKey : public HashTableKey { ...@@ -5551,6 +5551,46 @@ class StringKey : public HashTableKey {
String* string_; String* string_;
}; };
// RegExpKey carries the source and flags of a regular expression as key.
class RegExpKey : public HashTableKey {
public:
RegExpKey(String* string, JSRegExp::Flags flags)
: string_(string),
flags_(Smi::FromInt(flags.value())) { }
bool IsMatch(Object* obj) {
FixedArray* val = FixedArray::cast(obj);
return string_->Equals(String::cast(val->get(JSRegExp::kSourceIndex)))
&& (flags_ == val->get(JSRegExp::kFlagsIndex));
}
uint32_t Hash() { return RegExpHash(string_, flags_); }
HashFunction GetHashFunction() { return RegExpObjectHash; }
Object* GetObject() {
// Plain hash maps, which is where regexp keys are used, don't
// use this function.
UNREACHABLE();
return NULL;
}
static uint32_t RegExpObjectHash(Object* obj) {
FixedArray* val = FixedArray::cast(obj);
return RegExpHash(String::cast(val->get(JSRegExp::kSourceIndex)),
Smi::cast(val->get(JSRegExp::kFlagsIndex)));
}
static uint32_t RegExpHash(String* string, Smi* flags) {
return string->Hash() + flags->value();
}
bool IsStringKey() { return false; }
String* string_;
Smi* flags_;
};
// Utf8SymbolKey carries a vector of chars as key. // Utf8SymbolKey carries a vector of chars as key.
class Utf8SymbolKey : public HashTableKey { class Utf8SymbolKey : public HashTableKey {
public: public:
...@@ -5825,6 +5865,15 @@ Object* CompilationCacheTable::Lookup(String* src) { ...@@ -5825,6 +5865,15 @@ Object* CompilationCacheTable::Lookup(String* src) {
} }
Object* CompilationCacheTable::LookupRegExp(String* src,
JSRegExp::Flags flags) {
RegExpKey key(src, flags);
int entry = FindEntry(&key);
if (entry == -1) return Heap::undefined_value();
return get(EntryToIndex(entry) + 1);
}
Object* CompilationCacheTable::Put(String* src, Object* value) { Object* CompilationCacheTable::Put(String* src, Object* value) {
StringKey key(src); StringKey key(src);
Object* obj = EnsureCapacity(1, &key); Object* obj = EnsureCapacity(1, &key);
...@@ -5840,6 +5889,23 @@ Object* CompilationCacheTable::Put(String* src, Object* value) { ...@@ -5840,6 +5889,23 @@ Object* CompilationCacheTable::Put(String* src, Object* value) {
} }
Object* CompilationCacheTable::PutRegExp(String* src,
JSRegExp::Flags flags,
FixedArray* value) {
RegExpKey key(src, flags);
Object* obj = EnsureCapacity(1, &key);
if (obj->IsFailure()) return obj;
CompilationCacheTable* cache =
reinterpret_cast<CompilationCacheTable*>(obj);
int entry = cache->FindInsertionEntry(value, key.Hash());
cache->set(EntryToIndex(entry), value);
cache->set(EntryToIndex(entry) + 1, value);
cache->ElementAdded();
return cache;
}
// SymbolsKey used for HashTable where key is array of symbols. // SymbolsKey used for HashTable where key is array of symbols.
class SymbolsKey : public HashTableKey { class SymbolsKey : public HashTableKey {
public: public:
......
...@@ -1856,19 +1856,6 @@ class SymbolTable: public HashTable<0, 1> { ...@@ -1856,19 +1856,6 @@ class SymbolTable: public HashTable<0, 1> {
}; };
class CompilationCacheTable: public HashTable<0, 2> {
public:
// Find cached value for a string key, otherwise return null.
Object* Lookup(String* src);
Object* Put(String* src, Object* value);
static inline CompilationCacheTable* cast(Object* obj);
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(CompilationCacheTable);
};
// MapCache. // MapCache.
// //
// Maps keys that are a fixed array of symbols to a map. // Maps keys that are a fixed array of symbols to a map.
...@@ -2907,18 +2894,28 @@ class JSValue: public JSObject { ...@@ -2907,18 +2894,28 @@ class JSValue: public JSObject {
DISALLOW_IMPLICIT_CONSTRUCTORS(JSValue); DISALLOW_IMPLICIT_CONSTRUCTORS(JSValue);
}; };
// Regular expressions // Regular expressions
class JSRegExp: public JSObject { class JSRegExp: public JSObject {
public: public:
enum Type { JSCRE, ATOM }; enum Type { NOT_COMPILED, JSCRE, ATOM };
enum Flag { NONE = 0, GLOBAL = 1, IGNORE_CASE = 2, MULTILINE = 4 };
inline Type type_tag(); class Flags {
inline void set_type_tag(Type value); public:
explicit Flags(uint32_t value) : value_(value) { }
bool is_global() { return (value_ & GLOBAL) != 0; }
bool is_ignore_case() { return (value_ & IGNORE_CASE) != 0; }
bool is_multiline() { return (value_ & MULTILINE) != 0; }
uint32_t value() { return value_; }
private:
uint32_t value_;
};
DECL_ACCESSORS(type, Object)
DECL_ACCESSORS(data, Object) DECL_ACCESSORS(data, Object)
inline Type TypeTag();
inline Object* DataAt(int index);
static inline JSRegExp* cast(Object* obj); static inline JSRegExp* cast(Object* obj);
// Dispatched behavior. // Dispatched behavior.
...@@ -2927,9 +2924,32 @@ class JSRegExp: public JSObject { ...@@ -2927,9 +2924,32 @@ class JSRegExp: public JSObject {
void JSRegExpVerify(); void JSRegExpVerify();
#endif #endif
static const int kTypeOffset = JSObject::kHeaderSize; static const int kDataOffset = JSObject::kHeaderSize;
static const int kDataOffset = kTypeOffset + kIntSize;
static const int kSize = kDataOffset + kIntSize; static const int kSize = kDataOffset + kIntSize;
static const int kTagIndex = 0;
static const int kSourceIndex = kTagIndex + 1;
static const int kFlagsIndex = kSourceIndex + 1;
// These two are the same since the same entry is shared for
// different purposes in different types of regexps.
static const int kAtomPatternIndex = kFlagsIndex + 1;
static const int kJscreDataIndex = kFlagsIndex + 1;
static const int kDataSize = kAtomPatternIndex + 1;
};
class CompilationCacheTable: public HashTable<0, 2> {
public:
// Find cached value for a string key, otherwise return null.
Object* Lookup(String* src);
Object* LookupRegExp(String* source, JSRegExp::Flags flags);
Object* Put(String* src, Object* value);
Object* PutRegExp(String* src, JSRegExp::Flags flags, FixedArray* value);
static inline CompilationCacheTable* cast(Object* obj);
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(CompilationCacheTable);
}; };
......
...@@ -73,6 +73,8 @@ namespace v8 { namespace internal { ...@@ -73,6 +73,8 @@ namespace v8 { namespace internal {
SC(arguments_adaptors, V8.ArgumentsAdaptors) \ SC(arguments_adaptors, V8.ArgumentsAdaptors) \
SC(compilation_cache_hits, V8.CompilationCacheHits) \ SC(compilation_cache_hits, V8.CompilationCacheHits) \
SC(compilation_cache_misses, V8.CompilationCacheMisses) \ SC(compilation_cache_misses, V8.CompilationCacheMisses) \
SC(regexp_cache_hits, V8.RegExpCacheHits) \
SC(regexp_cache_misses, V8.RegExpCacheMisses) \
/* Amount of evaled source code. */ \ /* Amount of evaled source code. */ \
SC(total_eval_size, V8.TotalEvalSize) \ SC(total_eval_size, V8.TotalEvalSize) \
/* Amount of loaded source code. */ \ /* Amount of loaded source code. */ \
......
...@@ -222,13 +222,13 @@ class CompactProgressIndicator(ProgressIndicator): ...@@ -222,13 +222,13 @@ class CompactProgressIndicator(ProgressIndicator):
if output.UnexpectedOutput(): if output.UnexpectedOutput():
self.ClearLine(self.last_status_length) self.ClearLine(self.last_status_length)
self.PrintFailureHeader(output.test) self.PrintFailureHeader(output.test)
print "Command: %s" % EscapeCommand(output.command)
stdout = output.output.stdout.strip() stdout = output.output.stdout.strip()
if len(stdout): if len(stdout):
print self.templates['stdout'] % stdout print self.templates['stdout'] % stdout
stderr = output.output.stderr.strip() stderr = output.output.stderr.strip()
if len(stderr): if len(stderr):
print self.templates['stderr'] % stderr print self.templates['stderr'] % stderr
print "Command: %s" % EscapeCommand(output.command)
def Truncate(self, str, length): def Truncate(self, str, length):
if length and (len(str) > (length - 3)): if length and (len(str) > (length - 3)):
......
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