Commit e3f34a58 authored by bmeurer@chromium.org's avatar bmeurer@chromium.org

Reintroduce runtime zone to Isolate.

In case tcmalloc is not being used, the malloc()/free() overhead
can be significant for several runtime functions like StringReplace.
Therefore we reintroduce the runtime_zone into Isolate and reenable
the segment caching functionality of Zone.

There's now also a simpler version of ZoneScope w/o nesting capabilities.

BUG=v8:2759
R=danno@chromium.org, yangguo@chromium.org

Review URL: https://codereview.chromium.org/18635003

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@15465 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 56ab3e34
...@@ -1762,6 +1762,7 @@ Isolate::Isolate() ...@@ -1762,6 +1762,7 @@ Isolate::Isolate()
descriptor_lookup_cache_(NULL), descriptor_lookup_cache_(NULL),
handle_scope_implementer_(NULL), handle_scope_implementer_(NULL),
unicode_cache_(NULL), unicode_cache_(NULL),
runtime_zone_(this),
in_use_list_(0), in_use_list_(0),
free_list_(0), free_list_(0),
preallocated_storage_preallocated_(false), preallocated_storage_preallocated_(false),
...@@ -1960,6 +1961,9 @@ void Isolate::SetIsolateThreadLocals(Isolate* isolate, ...@@ -1960,6 +1961,9 @@ void Isolate::SetIsolateThreadLocals(Isolate* isolate,
Isolate::~Isolate() { Isolate::~Isolate() {
TRACE_ISOLATE(destructor); TRACE_ISOLATE(destructor);
// Has to be called while counters_ are still alive
runtime_zone_.DeleteKeptSegment();
// The entry stack must be empty when we get here, // The entry stack must be empty when we get here,
// except for the default isolate, where it can // except for the default isolate, where it can
// still contain up to one entry stack item // still contain up to one entry stack item
......
...@@ -896,6 +896,7 @@ class Isolate { ...@@ -896,6 +896,7 @@ class Isolate {
ASSERT(handle_scope_implementer_); ASSERT(handle_scope_implementer_);
return handle_scope_implementer_; return handle_scope_implementer_;
} }
Zone* runtime_zone() { return &runtime_zone_; }
UnicodeCache* unicode_cache() { UnicodeCache* unicode_cache() {
return unicode_cache_; return unicode_cache_;
...@@ -1270,6 +1271,7 @@ class Isolate { ...@@ -1270,6 +1271,7 @@ class Isolate {
v8::ImplementationUtilities::HandleScopeData handle_scope_data_; v8::ImplementationUtilities::HandleScopeData handle_scope_data_;
HandleScopeImplementer* handle_scope_implementer_; HandleScopeImplementer* handle_scope_implementer_;
UnicodeCache* unicode_cache_; UnicodeCache* unicode_cache_;
Zone runtime_zone_;
PreallocatedStorage in_use_list_; PreallocatedStorage in_use_list_;
PreallocatedStorage free_list_; PreallocatedStorage free_list_;
bool preallocated_storage_preallocated_; bool preallocated_storage_preallocated_;
......
...@@ -3598,8 +3598,8 @@ MUST_USE_RESULT static MaybeObject* StringReplaceGlobalAtomRegExpWithString( ...@@ -3598,8 +3598,8 @@ MUST_USE_RESULT static MaybeObject* StringReplaceGlobalAtomRegExpWithString(
ASSERT(subject->IsFlat()); ASSERT(subject->IsFlat());
ASSERT(replacement->IsFlat()); ASSERT(replacement->IsFlat());
Zone zone(isolate); ZoneScope zone_scope(isolate->runtime_zone());
ZoneList<int> indices(8, &zone); ZoneList<int> indices(8, zone_scope.zone());
ASSERT_EQ(JSRegExp::ATOM, pattern_regexp->TypeTag()); ASSERT_EQ(JSRegExp::ATOM, pattern_regexp->TypeTag());
String* pattern = String* pattern =
String::cast(pattern_regexp->DataAt(JSRegExp::kAtomPatternIndex)); String::cast(pattern_regexp->DataAt(JSRegExp::kAtomPatternIndex));
...@@ -3608,7 +3608,7 @@ MUST_USE_RESULT static MaybeObject* StringReplaceGlobalAtomRegExpWithString( ...@@ -3608,7 +3608,7 @@ MUST_USE_RESULT static MaybeObject* StringReplaceGlobalAtomRegExpWithString(
int replacement_len = replacement->length(); int replacement_len = replacement->length();
FindStringIndicesDispatch( FindStringIndicesDispatch(
isolate, *subject, pattern, &indices, 0xffffffff, &zone); isolate, *subject, pattern, &indices, 0xffffffff, zone_scope.zone());
int matches = indices.length(); int matches = indices.length();
if (matches == 0) return *subject; if (matches == 0) return *subject;
...@@ -3684,8 +3684,8 @@ MUST_USE_RESULT static MaybeObject* StringReplaceGlobalRegExpWithString( ...@@ -3684,8 +3684,8 @@ MUST_USE_RESULT static MaybeObject* StringReplaceGlobalRegExpWithString(
int subject_length = subject->length(); int subject_length = subject->length();
// CompiledReplacement uses zone allocation. // CompiledReplacement uses zone allocation.
Zone zone(isolate); ZoneScope zone_scope(isolate->runtime_zone());
CompiledReplacement compiled_replacement(&zone); CompiledReplacement compiled_replacement(zone_scope.zone());
bool simple_replace = compiled_replacement.Compile(replacement, bool simple_replace = compiled_replacement.Compile(replacement,
capture_count, capture_count,
subject_length); subject_length);
...@@ -4218,14 +4218,14 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) { ...@@ -4218,14 +4218,14 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
int capture_count = regexp->CaptureCount(); int capture_count = regexp->CaptureCount();
Zone zone(isolate); ZoneScope zone_scope(isolate->runtime_zone());
ZoneList<int> offsets(8, &zone); ZoneList<int> offsets(8, zone_scope.zone());
while (true) { while (true) {
int32_t* match = global_cache.FetchNext(); int32_t* match = global_cache.FetchNext();
if (match == NULL) break; if (match == NULL) break;
offsets.Add(match[0], &zone); // start offsets.Add(match[0], zone_scope.zone()); // start
offsets.Add(match[1], &zone); // end offsets.Add(match[1], zone_scope.zone()); // end
} }
if (global_cache.HasException()) return Failure::Exception(); if (global_cache.HasException()) return Failure::Exception();
...@@ -6310,18 +6310,18 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) { ...@@ -6310,18 +6310,18 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
static const int kMaxInitialListCapacity = 16; static const int kMaxInitialListCapacity = 16;
Zone zone(isolate); ZoneScope zone_scope(isolate->runtime_zone());
// Find (up to limit) indices of separator and end-of-string in subject // Find (up to limit) indices of separator and end-of-string in subject
int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit); int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
ZoneList<int> indices(initial_capacity, &zone); ZoneList<int> indices(initial_capacity, zone_scope.zone());
if (!pattern->IsFlat()) FlattenString(pattern); if (!pattern->IsFlat()) FlattenString(pattern);
FindStringIndicesDispatch(isolate, *subject, *pattern, FindStringIndicesDispatch(isolate, *subject, *pattern,
&indices, limit, &zone); &indices, limit, zone_scope.zone());
if (static_cast<uint32_t>(indices.length()) < limit) { if (static_cast<uint32_t>(indices.length()) < limit) {
indices.Add(subject_length, &zone); indices.Add(subject_length, zone_scope.zone());
} }
// The list indices now contains the end of each part to create. // The list indices now contains the end of each part to create.
......
...@@ -78,31 +78,82 @@ Zone::Zone(Isolate* isolate) ...@@ -78,31 +78,82 @@ Zone::Zone(Isolate* isolate)
Zone::~Zone() { Zone::~Zone() {
DeleteAll();
DeleteKeptSegment();
ASSERT(segment_bytes_allocated_ == 0);
}
void Zone::DeleteAll() {
#ifdef DEBUG #ifdef DEBUG
// Constant byte value used for zapping dead memory in debug mode. // Constant byte value used for zapping dead memory in debug mode.
static const unsigned char kZapDeadByte = 0xcd; static const unsigned char kZapDeadByte = 0xcd;
#endif #endif
// Traverse the chained list of segments, zapping // Find a segment with a suitable size to keep around.
// (in debug mode) and freeing every segment Segment* keep = segment_head_;
Segment* current = segment_head_; while (keep != NULL && keep->size() > kMaximumKeptSegmentSize) {
while (current != NULL) { keep = keep->next();
}
// Traverse the chained list of segments, zapping (in debug mode)
// and freeing every segment except the one we wish to keep.
for (Segment* current = segment_head_; current != NULL; ) {
Segment* next = current->next(); Segment* next = current->next();
int size = current->size(); if (current == keep) {
// Unlink the segment we wish to keep from the list.
current->clear_next();
} else {
int size = current->size();
#ifdef DEBUG #ifdef DEBUG
// Zap the entire current segment (including the header). // Zap the entire current segment (including the header).
memset(current, kZapDeadByte, size); memset(current, kZapDeadByte, size);
#endif #endif
DeleteSegment(current, size); DeleteSegment(current, size);
}
current = next; current = next;
} }
// We must clear the position and limit to force // If we have found a segment we want to keep, we must recompute the
// a new segment to be allocated on demand. // variables 'position' and 'limit' to prepare for future allocate
position_ = limit_ = 0; // attempts. Otherwise, we must clear the position and limit to
// force a new segment to be allocated on demand.
if (keep != NULL) {
Address start = keep->start();
position_ = RoundUp(start, kAlignment);
limit_ = keep->end();
#ifdef DEBUG
// Zap the contents of the kept segment (but not the header).
memset(start, kZapDeadByte, keep->capacity());
#endif
} else {
position_ = limit_ = 0;
}
// Update the head segment to be the kept segment (if any).
segment_head_ = keep;
}
void Zone::DeleteKeptSegment() {
#ifdef DEBUG
// Constant byte value used for zapping dead memory in debug mode.
static const unsigned char kZapDeadByte = 0xcd;
#endif
ASSERT(segment_head_ == NULL || segment_head_->next() == NULL);
if (segment_head_ != NULL) {
int size = segment_head_->size();
#ifdef DEBUG
// Zap the entire kept segment (including the header).
memset(segment_head_, kZapDeadByte, size);
#endif
DeleteSegment(segment_head_, size);
segment_head_ = NULL;
}
// Update the head segment. ASSERT(segment_bytes_allocated_ == 0);
segment_head_ = NULL;
} }
......
...@@ -66,6 +66,14 @@ class Zone { ...@@ -66,6 +66,14 @@ class Zone {
template <typename T> template <typename T>
inline T* NewArray(int length); inline T* NewArray(int length);
// Deletes all objects and free all memory allocated in the Zone. Keeps one
// small (size <= kMaximumKeptSegmentSize) segment around if it finds one.
void DeleteAll();
// Deletes the last small segment kept around by DeleteAll(). You
// may no longer allocate in the Zone after a call to this method.
void DeleteKeptSegment();
// Returns true if more memory has been allocated in zones than // Returns true if more memory has been allocated in zones than
// the limit allows. // the limit allows.
inline bool excess_allocation(); inline bool excess_allocation();
...@@ -90,6 +98,9 @@ class Zone { ...@@ -90,6 +98,9 @@ class Zone {
// Never allocate segments larger than this size in bytes. // Never allocate segments larger than this size in bytes.
static const int kMaximumSegmentSize = 1 * MB; static const int kMaximumSegmentSize = 1 * MB;
// Never keep segments larger than this size in bytes around.
static const int kMaximumKeptSegmentSize = 64 * KB;
// Report zone excess when allocation exceeds this limit. // Report zone excess when allocation exceeds this limit.
static const int kExcessLimit = 256 * MB; static const int kExcessLimit = 256 * MB;
...@@ -109,10 +120,10 @@ class Zone { ...@@ -109,10 +120,10 @@ class Zone {
// Creates a new segment, sets it size, and pushes it to the front // Creates a new segment, sets it size, and pushes it to the front
// of the segment chain. Returns the new segment. // of the segment chain. Returns the new segment.
Segment* NewSegment(int size); INLINE(Segment* NewSegment(int size));
// Deletes the given segment. Does not touch the segment chain. // Deletes the given segment. Does not touch the segment chain.
void DeleteSegment(Segment* segment, int size); INLINE(void DeleteSegment(Segment* segment, int size));
// The free region in the current (front) segment is represented as // The free region in the current (front) segment is represented as
// the half-open interval [position, limit). The 'position' variable // the half-open interval [position, limit). The 'position' variable
...@@ -145,6 +156,20 @@ class ZoneObject { ...@@ -145,6 +156,20 @@ class ZoneObject {
}; };
// The ZoneScope is used to automatically call DeleteAll() on a
// Zone when the ZoneScope is destroyed (i.e. goes out of scope)
struct ZoneScope {
public:
explicit ZoneScope(Zone* zone) : zone_(zone) { }
~ZoneScope() { zone_->DeleteAll(); }
Zone* zone() { return zone_; }
private:
Zone* zone_;
};
// The ZoneAllocationPolicy is used to specialize generic data // The ZoneAllocationPolicy is used to specialize generic data
// structures to allocate themselves and their elements in the Zone. // structures to allocate themselves and their elements in the Zone.
struct ZoneAllocationPolicy { struct ZoneAllocationPolicy {
......
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