Debugger: use weak cells to implement ScriptCache.

R=ulan@chromium.org

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

Cr-Commit-Position: refs/heads/master@{#28539}
This commit is contained in:
yangguo 2015-05-21 03:35:51 -07:00 committed by Commit bot
parent 29deaef505
commit 720d9c280a
5 changed files with 112 additions and 91 deletions

View File

@ -493,8 +493,7 @@ int Debug::ArchiveSpacePerThread() {
}
ScriptCache::ScriptCache(Isolate* isolate) : HashMap(HashMap::PointersMatch),
isolate_(isolate) {
ScriptCache::ScriptCache(Isolate* isolate) : isolate_(isolate) {
Heap* heap = isolate_->heap();
HandleScope scope(isolate_);
@ -502,92 +501,53 @@ ScriptCache::ScriptCache(Isolate* isolate) : HashMap(HashMap::PointersMatch),
heap->CollectAllGarbage(Heap::kMakeHeapIterableMask, "ScriptCache");
// Scan heap for Script objects.
HeapIterator iterator(heap);
DisallowHeapAllocation no_allocation;
for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
if (obj->IsScript() && Script::cast(obj)->HasValidSource()) {
Add(Handle<Script>(Script::cast(obj)));
List<Handle<Script> > scripts;
{
HeapIterator iterator(heap, HeapIterator::kFilterUnreachable);
DisallowHeapAllocation no_allocation;
for (HeapObject* obj = iterator.next(); obj != NULL;
obj = iterator.next()) {
if (obj->IsScript() && Script::cast(obj)->HasValidSource()) {
scripts.Add(Handle<Script>(Script::cast(obj)));
}
}
}
GlobalHandles* global_handles = isolate_->global_handles();
table_ = Handle<WeakValueHashTable>::cast(global_handles->Create(
Object::cast(*WeakValueHashTable::New(isolate_, scripts.length()))));
for (int i = 0; i < scripts.length(); i++) Add(scripts[i]);
}
void ScriptCache::Add(Handle<Script> script) {
GlobalHandles* global_handles = isolate_->global_handles();
// Create an entry in the hash map for the script.
int id = script->id()->value();
HashMap::Entry* entry =
HashMap::LookupOrInsert(reinterpret_cast<void*>(id), Hash(id));
if (entry->value != NULL) {
HandleScope scope(isolate_);
Handle<Smi> id(script->id(), isolate_);
#ifdef DEBUG
// The code deserializer may introduce duplicate Script objects.
// Assert that the Script objects with the same id have the same name.
Handle<Script> found(reinterpret_cast<Script**>(entry->value));
Handle<Object> lookup(table_->LookupWeak(id), isolate_);
if (!lookup->IsTheHole()) {
Handle<Script> found = Handle<Script>::cast(lookup);
DCHECK(script->id() == found->id());
DCHECK(!script->name()->IsString() ||
String::cast(script->name())->Equals(String::cast(found->name())));
}
#endif
return;
}
// Globalize the script object, make it weak and use the location of the
// global handle as the value in the hash map.
Handle<Script> script_ =
Handle<Script>::cast(global_handles->Create(*script));
GlobalHandles::MakeWeak(reinterpret_cast<Object**>(script_.location()),
this,
ScriptCache::HandleWeakScript);
entry->value = script_.location();
Handle<WeakValueHashTable> new_table =
WeakValueHashTable::PutWeak(table_, id, script);
if (new_table.is_identical_to(table_)) return;
GlobalHandles* global_handles = isolate_->global_handles();
global_handles->Destroy(Handle<Object>::cast(table_).location());
table_ = Handle<WeakValueHashTable>::cast(
global_handles->Create(Object::cast(*new_table)));
}
Handle<FixedArray> ScriptCache::GetScripts() {
Factory* factory = isolate_->factory();
Handle<FixedArray> instances = factory->NewFixedArray(occupancy());
int count = 0;
for (HashMap::Entry* entry = Start(); entry != NULL; entry = Next(entry)) {
DCHECK(entry->value != NULL);
if (entry->value != NULL) {
instances->set(count, *reinterpret_cast<Script**>(entry->value));
count++;
}
}
return instances;
}
void ScriptCache::Clear() {
// Iterate the script cache to get rid of all the weak handles.
for (HashMap::Entry* entry = Start(); entry != NULL; entry = Next(entry)) {
DCHECK(entry != NULL);
Object** location = reinterpret_cast<Object**>(entry->value);
DCHECK((*location)->IsScript());
GlobalHandles::ClearWeakness(location);
GlobalHandles::Destroy(location);
}
// Clear the content of the hash map.
HashMap::Clear();
}
void ScriptCache::HandleWeakScript(
const v8::WeakCallbackData<v8::Value, void>& data) {
// Retrieve the script identifier.
Handle<Object> object = Utils::OpenHandle(*data.GetValue());
int id = Handle<Script>::cast(object)->id()->value();
void* key = reinterpret_cast<void*>(id);
uint32_t hash = Hash(id);
// Remove the corresponding entry from the cache.
ScriptCache* script_cache =
reinterpret_cast<ScriptCache*>(data.GetParameter());
HashMap::Entry* entry = script_cache->Lookup(key, hash);
DCHECK_NOT_NULL(entry);
Object** location = reinterpret_cast<Object**>(entry->value);
script_cache->Remove(key, hash);
// Clear the weak handle.
GlobalHandles::Destroy(location);
ScriptCache::~ScriptCache() {
isolate_->global_handles()->Destroy(Handle<Object>::cast(table_).location());
table_ = Handle<WeakValueHashTable>();
}

View File

@ -228,31 +228,22 @@ class BreakLocation {
// to it is created and that weak handle is stored in the cache. The weak handle
// callback takes care of removing the script from the cache. The key used in
// the cache is the script id.
class ScriptCache : private HashMap {
class ScriptCache {
public:
explicit ScriptCache(Isolate* isolate);
virtual ~ScriptCache() { Clear(); }
~ScriptCache();
// Add script to the cache.
void Add(Handle<Script> script);
// Return the scripts in the cache.
Handle<FixedArray> GetScripts();
private:
// Calculate the hash value from the key (script id).
static uint32_t Hash(int key) {
return ComputeIntegerHash(key, v8::internal::kZeroHashSeed);
Handle<FixedArray> GetScripts() {
return WeakValueHashTable::GetWeakValues(table_);
}
// Clear the cache releasing all the weak handles.
void Clear();
// Weak handle callback for scripts in the cache.
static void HandleWeakScript(
const v8::WeakCallbackData<v8::Value, void>& data);
private:
Isolate* isolate_;
Handle<WeakValueHashTable> table_;
};

View File

@ -891,6 +891,9 @@ bool Object::IsWeakHashTable() const {
}
bool Object::IsWeakValueHashTable() const { return IsHashTable(); }
bool Object::IsDictionary() const {
return IsHashTable() &&
this != HeapObject::cast(this)->GetHeap()->string_table();
@ -3436,6 +3439,7 @@ CAST_ACCESSOR(UnseededNumberDictionary)
CAST_ACCESSOR(WeakCell)
CAST_ACCESSOR(WeakFixedArray)
CAST_ACCESSOR(WeakHashTable)
CAST_ACCESSOR(WeakValueHashTable)
// static

View File

@ -16411,6 +16411,49 @@ void WeakHashTable::AddEntry(int entry, Handle<WeakCell> key_cell,
}
#ifdef DEBUG
Object* WeakValueHashTable::LookupWeak(Handle<Object> key) {
Object* value = Lookup(key);
if (value->IsWeakCell() && !WeakCell::cast(value)->cleared()) {
value = WeakCell::cast(value)->value();
}
return value;
}
#endif // DEBUG
Handle<WeakValueHashTable> WeakValueHashTable::PutWeak(
Handle<WeakValueHashTable> table, Handle<Object> key,
Handle<HeapObject> value) {
Handle<WeakCell> cell = value->GetIsolate()->factory()->NewWeakCell(value);
return Handle<WeakValueHashTable>::cast(
Put(Handle<ObjectHashTable>::cast(table), key, cell));
}
Handle<FixedArray> WeakValueHashTable::GetWeakValues(
Handle<WeakValueHashTable> table) {
Isolate* isolate = table->GetIsolate();
uint32_t capacity = table->Capacity();
Handle<FixedArray> results = isolate->factory()->NewFixedArray(capacity);
int length = 0;
for (uint32_t i = 0; i < capacity; i++) {
uint32_t key_index = table->EntryToIndex(i);
Object* key = table->get(key_index);
if (!table->IsKey(key)) continue;
uint32_t value_index = table->EntryToValueIndex(i);
WeakCell* value_cell = WeakCell::cast(table->get(value_index));
if (value_cell->cleared()) {
table->RemoveEntry(i);
} else {
results->set(length++, value_cell->value());
}
}
results->Shrink(length);
return results;
}
template<class Derived, class Iterator, int entrysize>
Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Allocate(
Isolate* isolate, int capacity, PretenureFlag pretenure) {

View File

@ -1012,6 +1012,7 @@ template <class C> inline bool Is(Object* obj);
V(WeakCell) \
V(ObjectHashTable) \
V(WeakHashTable) \
V(WeakValueHashTable) \
V(OrderedHashTable)
// Object is the abstract superclass for all classes in the
@ -3958,7 +3959,7 @@ class ObjectHashTable: public HashTable<ObjectHashTable,
Handle<Object> key,
bool* was_present);
private:
protected:
friend class MarkCompactCollector;
void AddEntry(int entry, Object* key, Object* value);
@ -4185,6 +4186,8 @@ class WeakHashTable: public HashTable<WeakHashTable,
Handle<HeapObject> key,
Handle<HeapObject> value);
static Handle<FixedArray> GetValues(Handle<WeakHashTable> table);
private:
friend class MarkCompactCollector;
@ -4197,6 +4200,26 @@ class WeakHashTable: public HashTable<WeakHashTable,
};
class WeakValueHashTable : public ObjectHashTable {
public:
DECLARE_CAST(WeakValueHashTable)
#ifdef DEBUG
// Looks up the value associated with the given key. The hole value is
// returned in case the key is not present.
Object* LookupWeak(Handle<Object> key);
#endif // DEBUG
// Adds (or overwrites) the value associated with the given key. Mapping a
// key to the hole value causes removal of the whole entry.
MUST_USE_RESULT static Handle<WeakValueHashTable> PutWeak(
Handle<WeakValueHashTable> table, Handle<Object> key,
Handle<HeapObject> value);
static Handle<FixedArray> GetWeakValues(Handle<WeakValueHashTable> table);
};
// JSFunctionResultCache caches results of some JSFunction invocation.
// It is a fixed array with fixed structure:
// [0]: factory function
@ -4204,7 +4227,7 @@ class WeakHashTable: public HashTable<WeakHashTable,
// [2]: current cache size
// [3]: dummy field.
// The rest of array are key/value pairs.
class JSFunctionResultCache: public FixedArray {
class JSFunctionResultCache : public FixedArray {
public:
static const int kFactoryIndex = 0;
static const int kFingerIndex = kFactoryIndex + 1;