Introduce SharedFunctionInfo::Iterator and Script::Iterator.
authoryangguo <yangguo@chromium.org>
Fri, 21 Aug 2015 08:12:11 +0000 (01:12 -0700)
committerCommit bot <commit-bot@chromium.org>
Fri, 21 Aug 2015 08:12:27 +0000 (08:12 +0000)
R=mvstanton@chromium.org

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

Cr-Commit-Position: refs/heads/master@{#30283}

src/debug/debug.cc
src/heap/heap.cc
src/objects-inl.h
src/objects.cc
src/objects.h
src/runtime/runtime-debug.cc
test/cctest/test-heap.cc

index 2bda0a7137a12323e2f112be99bc07b4d452fb29..6a491384440a7c000e5ee70d04c7a14a7215f98e 100644 (file)
@@ -1424,17 +1424,17 @@ Handle<Object> Debug::FindSharedFunctionInfoInScript(Handle<Script> script,
   while (true) {
     // Go through all shared function infos associated with this script to
     // find the inner most function containing this position.
+    // If there is no shared function info for this script at all, there is
+    // no point in looking for it by walking the heap.
     if (!script->shared_function_infos()->IsWeakFixedArray()) break;
-    WeakFixedArray* array =
-        WeakFixedArray::cast(script->shared_function_infos());
 
     SharedFunctionInfo* shared;
     {
       SharedFunctionInfoFinder finder(position);
-      for (int i = 0; i < array->Length(); i++) {
-        Object* item = array->Get(i);
-        if (!item->IsSharedFunctionInfo()) continue;
-        finder.NewCandidate(SharedFunctionInfo::cast(item));
+      WeakFixedArray::Iterator iterator(script->shared_function_infos());
+      SharedFunctionInfo* candidate;
+      while ((candidate = iterator.Next<SharedFunctionInfo>())) {
+        finder.NewCandidate(candidate);
       }
       shared = finder.Result();
       if (shared == NULL) break;
@@ -1608,8 +1608,7 @@ void Debug::ClearMirrorCache() {
 
 
 Handle<FixedArray> Debug::GetLoadedScripts() {
-  isolate_->heap()->CollectAllGarbage(Heap::kNoGCFlags,
-                                      "Debug::GetLoadedScripts");
+  isolate_->heap()->CollectAllGarbage();
   Factory* factory = isolate_->factory();
   if (!factory->script_list()->IsWeakFixedArray()) {
     return factory->empty_fixed_array();
@@ -1618,10 +1617,11 @@ Handle<FixedArray> Debug::GetLoadedScripts() {
       Handle<WeakFixedArray>::cast(factory->script_list());
   Handle<FixedArray> results = factory->NewFixedArray(array->Length());
   int length = 0;
-  for (int i = 0; i < array->Length(); ++i) {
-    Object* item = array->Get(i);
-    if (item->IsScript() && Script::cast(item)->HasValidSource()) {
-      results->set(length++, item);
+  {
+    Script::Iterator iterator(isolate_);
+    Script* script;
+    while ((script = iterator.Next())) {
+      if (script->HasValidSource()) results->set(length++, script);
     }
   }
   results->Shrink(length);
index 9cc4154d1f00cb60d65fcc13148d6e400c56256b..ef7030e7aaddb23b7e44519fb191fa3db35628d7 100644 (file)
@@ -715,12 +715,9 @@ void Heap::GarbageCollectionEpilogue() {
 
 
 void Heap::PreprocessStackTraces() {
-  if (!weak_stack_trace_list()->IsWeakFixedArray()) return;
-  WeakFixedArray* array = WeakFixedArray::cast(weak_stack_trace_list());
-  int length = array->Length();
-  for (int i = 0; i < length; i++) {
-    if (array->IsEmptySlot(i)) continue;
-    FixedArray* elements = FixedArray::cast(array->Get(i));
+  WeakFixedArray::Iterator iterator(weak_stack_trace_list());
+  FixedArray* elements;
+  while ((elements = iterator.Next<FixedArray>())) {
     for (int j = 1; j < elements->length(); j += 4) {
       Object* maybe_code = elements->get(j + 2);
       // If GC happens while adding a stack trace to the weak fixed array,
index 933360c59fa41a462ed9e3997e2346a0f59db395..04a47277438724bade6950f5c1bca2d7e7e0c3a9 100644 (file)
@@ -2523,6 +2523,21 @@ void WeakFixedArray::set_last_used_index(int index) {
 }
 
 
+template <class T>
+T* WeakFixedArray::Iterator::Next() {
+  if (list_ != NULL) {
+    // Assert that list did not change during iteration.
+    DCHECK_EQ(last_used_index_, list_->last_used_index());
+    while (index_ < list_->Length()) {
+      Object* item = list_->Get(index_++);
+      if (item != Empty()) return T::cast(item);
+    }
+    list_ = NULL;
+  }
+  return NULL;
+}
+
+
 int ArrayList::Length() {
   if (FixedArray::cast(this)->length() == 0) return 0;
   return Smi::cast(FixedArray::cast(this)->get(kLengthIndex))->value();
index 552d4f5516e3feaeb6f2ff9b6e838e5e8c465c34..9618c9dccd723f9640af71e219bff7aba0323207 100644 (file)
@@ -7816,6 +7816,17 @@ void WeakFixedArray::Compact() {
 }
 
 
+void WeakFixedArray::Iterator::Reset(Object* maybe_array) {
+  if (maybe_array->IsWeakFixedArray()) {
+    list_ = WeakFixedArray::cast(maybe_array);
+    index_ = 0;
+#ifdef DEBUG
+    last_used_index_ = list_->last_used_index();
+#endif  // DEBUG
+  }
+}
+
+
 void JSObject::PrototypeRegistryCompactionCallback::Callback(Object* value,
                                                              int old_index,
                                                              int new_index) {
@@ -9666,16 +9677,10 @@ static void InvalidatePrototypeChainsInternal(Map* map) {
     cell->set_value(Smi::FromInt(Map::kPrototypeChainInvalid));
   }
 
-  Object* maybe_array = proto_info->prototype_users();
-  if (!maybe_array->IsWeakFixedArray()) return;
-
-  WeakFixedArray* users = WeakFixedArray::cast(maybe_array);
-  for (int i = 0; i < users->Length(); ++i) {
-    Object* maybe_user = users->Get(i);
-    if (maybe_user->IsSmi()) continue;
-
-    // For now, only maps register themselves as users.
-    Map* user = Map::cast(maybe_user);
+  WeakFixedArray::Iterator iterator(proto_info->prototype_users());
+  // For now, only maps register themselves as users.
+  Map* user;
+  while ((user = iterator.Next<Map>())) {
     // Walk the prototype chain (backwards, towards leaf objects) if necessary.
     InvalidatePrototypeChainsInternal(user);
   }
@@ -10179,22 +10184,48 @@ Handle<JSObject> Script::GetWrapper(Handle<Script> script) {
 
 MaybeHandle<SharedFunctionInfo> Script::FindSharedFunctionInfo(
     FunctionLiteral* fun) {
-  if (shared_function_infos()->IsWeakFixedArray()) {
-    WeakFixedArray* array = WeakFixedArray::cast(shared_function_infos());
-    for (int i = 0; i < array->Length(); i++) {
-      Object* obj = array->Get(i);
-      if (!obj->IsSharedFunctionInfo()) continue;
-      SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
-      if (fun->function_token_position() == shared->function_token_position() &&
-          fun->start_position() == shared->start_position()) {
-        return Handle<SharedFunctionInfo>(shared);
-      }
+  WeakFixedArray::Iterator iterator(shared_function_infos());
+  SharedFunctionInfo* shared;
+  while ((shared = iterator.Next<SharedFunctionInfo>())) {
+    if (fun->function_token_position() == shared->function_token_position() &&
+        fun->start_position() == shared->start_position()) {
+      return Handle<SharedFunctionInfo>(shared);
     }
   }
   return MaybeHandle<SharedFunctionInfo>();
 }
 
 
+Script::Iterator::Iterator(Isolate* isolate)
+    : iterator_(isolate->heap()->script_list()) {}
+
+
+Script* Script::Iterator::Next() { return iterator_.Next<Script>(); }
+
+
+SharedFunctionInfo::Iterator::Iterator(Isolate* isolate)
+    : script_iterator_(isolate), sfi_iterator_(NULL) {
+  NextScript();
+}
+
+
+bool SharedFunctionInfo::Iterator::NextScript() {
+  Script* script = script_iterator_.Next();
+  if (script == NULL) return false;
+  sfi_iterator_.Reset(script->shared_function_infos());
+  return true;
+}
+
+
+SharedFunctionInfo* SharedFunctionInfo::Iterator::Next() {
+  do {
+    SharedFunctionInfo* next = sfi_iterator_.Next<SharedFunctionInfo>();
+    if (next != NULL) return next;
+  } while (NextScript());
+  return NULL;
+}
+
+
 void SharedFunctionInfo::SetScript(Handle<SharedFunctionInfo> shared,
                                    Handle<Object> script_object) {
   if (shared->script() == *script_object) return;
@@ -10212,10 +10243,11 @@ void SharedFunctionInfo::SetScript(Handle<SharedFunctionInfo> shared,
     Handle<Script> script = Handle<Script>::cast(script_object);
     Handle<Object> list(script->shared_function_infos(), shared->GetIsolate());
 #ifdef DEBUG
-    if (list->IsWeakFixedArray()) {
-      Handle<WeakFixedArray> array = Handle<WeakFixedArray>::cast(list);
-      for (int i = 0; i < array->Length(); ++i) {
-        DCHECK(array->Get(i) != *shared);
+    {
+      WeakFixedArray::Iterator iterator(*list);
+      SharedFunctionInfo* next;
+      while ((next = iterator.Next<SharedFunctionInfo>())) {
+        DCHECK_NE(next, *shared);
       }
     }
 #endif  // DEBUG
index 96da77ef636ca8f71e838e3c0d743287ab817df4..c8856d4c6b6f3f4772989652f5221745ae5dd821 100644 (file)
@@ -2515,6 +2515,24 @@ class WeakFixedArray : public FixedArray {
   inline bool IsEmptySlot(int index) const;
   static Object* Empty() { return Smi::FromInt(0); }
 
+  class Iterator {
+   public:
+    explicit Iterator(Object* maybe_array) : list_(NULL) { Reset(maybe_array); }
+    void Reset(Object* maybe_array);
+
+    template <class T>
+    inline T* Next();
+
+   private:
+    int index_;
+    WeakFixedArray* list_;
+#ifdef DEBUG
+    int last_used_index_;
+    DisallowHeapAllocation no_gc_;
+#endif  // DEBUG
+    DISALLOW_COPY_AND_ASSIGN(Iterator);
+  };
+
   DECLARE_CAST(WeakFixedArray)
 
  private:
@@ -5930,6 +5948,17 @@ class Script: public Struct {
   // that matches the function literal.  Return empty handle if not found.
   MaybeHandle<SharedFunctionInfo> FindSharedFunctionInfo(FunctionLiteral* fun);
 
+  // Iterate over all script objects on the heap.
+  class Iterator {
+   public:
+    explicit Iterator(Isolate* isolate);
+    Script* Next();
+
+   private:
+    WeakFixedArray::Iterator iterator_;
+    DISALLOW_COPY_AND_ASSIGN(Iterator);
+  };
+
   // Dispatched behavior.
   DECLARE_PRINTER(Script)
   DECLARE_VERIFIER(Script)
@@ -6393,6 +6422,23 @@ class SharedFunctionInfo: public HeapObject {
 
   void ResetForNewContext(int new_ic_age);
 
+  // Iterate over all shared function infos that are created from a script.
+  // That excludes shared function infos created for API functions and C++
+  // builtins.
+  class Iterator {
+   public:
+    explicit Iterator(Isolate* isolate);
+    SharedFunctionInfo* Next();
+
+   private:
+    bool NextScript();
+
+    Script::Iterator script_iterator_;
+    WeakFixedArray::Iterator sfi_iterator_;
+    DisallowHeapAllocation no_gc_;
+    DISALLOW_COPY_AND_ASSIGN(Iterator);
+  };
+
   DECLARE_CAST(SharedFunctionInfo)
 
   // Constants.
index 41372e46946314cfb1eee5ecd624c3b02ecd9313..5177528f482303a6ce296472bd0ba4568319edd2 100644 (file)
@@ -1602,13 +1602,10 @@ RUNTIME_FUNCTION(Runtime_GetScript) {
   CONVERT_ARG_HANDLE_CHECKED(String, script_name, 0);
 
   Handle<Script> found;
-  Heap* heap = isolate->heap();
   {
-    HeapIterator iterator(heap);
-    HeapObject* obj = NULL;
-    while ((obj = iterator.next()) != NULL) {
-      if (!obj->IsScript()) continue;
-      Script* script = Script::cast(obj);
+    Script::Iterator iterator(isolate);
+    Script* script = NULL;
+    while ((script = iterator.Next()) != NULL) {
       if (!script->name()->IsString()) continue;
       String* name = String::cast(script->name());
       if (name->Equals(*script_name)) {
@@ -1618,7 +1615,7 @@ RUNTIME_FUNCTION(Runtime_GetScript) {
     }
   }
 
-  if (found.is_null()) return heap->undefined_value();
+  if (found.is_null()) return isolate->heap()->undefined_value();
   return *Script::GetWrapper(found);
 }
 
index f0ba4c1c04d429d55ce00f06c29e61381697d2e6..48ec24b3581d090bf1b8c1ea4042c1393679ee0a 100644 (file)
@@ -6440,5 +6440,67 @@ TEST(ContextMeasure) {
   CHECK_LE(measure.Size(), size_upper_limit);
 }
 
+
+TEST(ScriptIterator) {
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
+  Isolate* isolate = CcTest::i_isolate();
+  Heap* heap = CcTest::heap();
+  LocalContext context;
+
+  heap->CollectAllGarbage();
+
+  int script_count = 0;
+  {
+    HeapIterator it(heap);
+    for (HeapObject* obj = it.next(); obj != NULL; obj = it.next()) {
+      if (obj->IsScript()) script_count++;
+    }
+  }
+
+  {
+    Script::Iterator iterator(isolate);
+    while (iterator.Next()) script_count--;
+  }
+
+  CHECK_EQ(0, script_count);
+}
+
+
+TEST(SharedFunctionInfoIterator) {
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
+  Isolate* isolate = CcTest::i_isolate();
+  Heap* heap = CcTest::heap();
+  LocalContext context;
+
+  heap->CollectAllGarbage();
+  heap->CollectAllGarbage();
+
+  int sfi_count = 0;
+  {
+    HeapIterator it(heap);
+    for (HeapObject* obj = it.next(); obj != NULL; obj = it.next()) {
+      if (!obj->IsSharedFunctionInfo()) continue;
+      // Shared function infos without a script (API functions or C++ builtins)
+      // are not returned by the iterator because they are not created from a
+      // script. They are not interesting for type feedback vector anyways.
+      SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
+      if (shared->script()->IsUndefined()) {
+        CHECK_EQ(0, shared->feedback_vector()->ICSlots());
+      } else {
+        sfi_count++;
+      }
+    }
+  }
+
+  {
+    SharedFunctionInfo::Iterator iterator(isolate);
+    while (iterator.Next()) sfi_count--;
+  }
+
+  CHECK_EQ(0, sfi_count);
+}
+
 }  // namespace internal
 }  // namespace v8