Debugger: remove duplicate heap iterations.
authoryangguo <yangguo@chromium.org>
Thu, 13 Aug 2015 16:26:02 +0000 (09:26 -0700)
committerCommit bot <commit-bot@chromium.org>
Thu, 13 Aug 2015 16:26:12 +0000 (16:26 +0000)
R=mlippautz@chromium.org

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

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

src/debug/liveedit.cc
src/debug/liveedit.h
src/objects.cc
src/objects.h
src/runtime/runtime-debug.cc
src/runtime/runtime-liveedit.cc
src/runtime/runtime-object.cc

index 17ac712..8312dd3 100644 (file)
@@ -900,23 +900,6 @@ MaybeHandle<JSArray> LiveEdit::GatherCompileInfo(Handle<Script> script,
 }
 
 
-void LiveEdit::WrapSharedFunctionInfos(Handle<JSArray> array) {
-  Isolate* isolate = array->GetIsolate();
-  HandleScope scope(isolate);
-  int len = GetArrayLength(array);
-  for (int i = 0; i < len; i++) {
-    Handle<SharedFunctionInfo> info(
-        SharedFunctionInfo::cast(
-            *Object::GetElement(isolate, array, i).ToHandleChecked()));
-    SharedInfoWrapper info_wrapper = SharedInfoWrapper::Create(isolate);
-    Handle<String> name_handle(String::cast(info->name()));
-    info_wrapper.SetProperties(name_handle, info->start_position(),
-                               info->end_position(), info);
-    SetElementSloppy(array, i, info_wrapper.GetJSArray());
-  }
-}
-
-
 // Visitor that finds all references to a particular code object,
 // including "CODE_TARGET" references in other code objects and replaces
 // them on the fly.
index d576e82..251368f 100644 (file)
@@ -81,8 +81,6 @@ class LiveEdit : AllStatic {
       Handle<Script> script,
       Handle<String> source);
 
-  static void WrapSharedFunctionInfos(Handle<JSArray> array);
-
   static void ReplaceFunctionCode(Handle<JSArray> new_compile_info_array,
                                   Handle<JSArray> shared_info_array);
 
index 69f3965..2cfc82d 100644 (file)
@@ -598,6 +598,16 @@ void JSObject::SetNormalizedProperty(Handle<JSObject> object,
 }
 
 
+bool Object::HasInPrototypeChain(Isolate* isolate, Object* target) {
+  PrototypeIterator iter(isolate, this, PrototypeIterator::START_AT_RECEIVER);
+  while (true) {
+    iter.AdvanceIgnoringProxies();
+    if (iter.IsAtEnd()) return false;
+    if (iter.IsAtEnd(target)) return true;
+  }
+}
+
+
 Map* Object::GetRootMap(Isolate* isolate) {
   DisallowHeapAllocation no_alloc;
   if (IsSmi()) {
index d780119..09698e9 100644 (file)
@@ -1165,6 +1165,8 @@ class Object {
   static inline Handle<Object> GetPrototypeSkipHiddenPrototypes(
       Isolate* isolate, Handle<Object> receiver);
 
+  bool HasInPrototypeChain(Isolate* isolate, Object* object);
+
   // Returns the permanent hash code associated with this object. May return
   // undefined if not yet created.
   Object* GetHash();
index 97c3ff4..d4acf79 100644 (file)
@@ -1360,76 +1360,6 @@ RUNTIME_FUNCTION(Runtime_DebugGetLoadedScripts) {
 }
 
 
-// Helper function used by Runtime_DebugReferencedBy below.
-static int DebugReferencedBy(HeapIterator* iterator, JSObject* target,
-                             Object* instance_filter, int max_references,
-                             FixedArray* instances, int instances_size,
-                             JSFunction* arguments_function) {
-  Isolate* isolate = target->GetIsolate();
-  SealHandleScope shs(isolate);
-  DisallowHeapAllocation no_allocation;
-
-  // Iterate the heap.
-  int count = 0;
-  JSObject* last = NULL;
-  HeapObject* heap_obj = NULL;
-  while (((heap_obj = iterator->next()) != NULL) &&
-         (max_references == 0 || count < max_references)) {
-    // Only look at all JSObjects.
-    if (heap_obj->IsJSObject()) {
-      // Skip context extension objects and argument arrays as these are
-      // checked in the context of functions using them.
-      JSObject* obj = JSObject::cast(heap_obj);
-      if (obj->IsJSContextExtensionObject() ||
-          obj->map()->GetConstructor() == arguments_function) {
-        continue;
-      }
-
-      // Check if the JS object has a reference to the object looked for.
-      if (obj->ReferencesObject(target)) {
-        // Check instance filter if supplied. This is normally used to avoid
-        // references from mirror objects (see Runtime_IsInPrototypeChain).
-        if (!instance_filter->IsUndefined()) {
-          for (PrototypeIterator iter(isolate, obj); !iter.IsAtEnd();
-               iter.Advance()) {
-            if (iter.GetCurrent() == instance_filter) {
-              obj = NULL;  // Don't add this object.
-              break;
-            }
-          }
-        }
-
-        // Do not expose the global object directly.
-        if (obj->IsJSGlobalObject()) {
-          obj = JSGlobalObject::cast(obj)->global_proxy();
-        }
-
-        if (obj != NULL) {
-          // Valid reference found add to instance array if supplied an update
-          // count.
-          if (instances != NULL && count < instances_size) {
-            instances->set(count, obj);
-          }
-          last = obj;
-          count++;
-        }
-      }
-    }
-  }
-
-  // Check for circular reference only. This can happen when the object is only
-  // referenced from mirrors and has a circular reference in which case the
-  // object is not really alive and would have been garbage collected if not
-  // referenced from the mirror.
-  if (count == 1 && last == target) {
-    count = 0;
-  }
-
-  // Return the number of referencing objects found.
-  return count;
-}
-
-
 // Scan the heap for objects with direct references to an object
 // args[0]: the object to find references to
 // args[1]: constructor function for instances to exclude (Mirror)
@@ -1437,79 +1367,54 @@ static int DebugReferencedBy(HeapIterator* iterator, JSObject* target,
 RUNTIME_FUNCTION(Runtime_DebugReferencedBy) {
   HandleScope scope(isolate);
   DCHECK(args.length() == 3);
-
-  // Check parameters.
   CONVERT_ARG_HANDLE_CHECKED(JSObject, target, 0);
-  CONVERT_ARG_HANDLE_CHECKED(Object, instance_filter, 1);
-  RUNTIME_ASSERT(instance_filter->IsUndefined() ||
-                 instance_filter->IsJSObject());
+  CONVERT_ARG_HANDLE_CHECKED(Object, filter, 1);
+  RUNTIME_ASSERT(filter->IsUndefined() || filter->IsJSObject());
   CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
   RUNTIME_ASSERT(max_references >= 0);
 
-
-  // Get the constructor function for context extension and arguments array.
-  Handle<JSFunction> arguments_function(
-      JSFunction::cast(isolate->sloppy_arguments_map()->GetConstructor()));
-
-  // Get the number of referencing objects.
-  int count;
-  // First perform a full GC in order to avoid dead objects and to make the heap
-  // iterable.
+  List<Handle<JSObject> > instances;
   Heap* heap = isolate->heap();
-  heap->CollectAllGarbage(Heap::kMakeHeapIterableMask, "%DebugConstructedBy");
-  {
-    HeapIterator heap_iterator(heap);
-    count = DebugReferencedBy(&heap_iterator, *target, *instance_filter,
-                              max_references, NULL, 0, *arguments_function);
-  }
-
-  // Allocate an array to hold the result.
-  Handle<FixedArray> instances = isolate->factory()->NewFixedArray(count);
-
-  // Fill the referencing objects.
   {
-    HeapIterator heap_iterator(heap);
-    count = DebugReferencedBy(&heap_iterator, *target, *instance_filter,
-                              max_references, *instances, count,
-                              *arguments_function);
-  }
-
-  // Return result as JS array.
-  Handle<JSFunction> constructor = isolate->array_function();
-
-  Handle<JSObject> result = isolate->factory()->NewJSObject(constructor);
-  JSArray::SetContent(Handle<JSArray>::cast(result), instances);
-  return *result;
-}
-
-
-// Helper function used by Runtime_DebugConstructedBy below.
-static int DebugConstructedBy(HeapIterator* iterator, JSFunction* constructor,
-                              int max_references, FixedArray* instances,
-                              int instances_size) {
-  DisallowHeapAllocation no_allocation;
-
-  // Iterate the heap.
-  int count = 0;
-  HeapObject* heap_obj = NULL;
-  while (((heap_obj = iterator->next()) != NULL) &&
-         (max_references == 0 || count < max_references)) {
-    // Only look at all JSObjects.
-    if (heap_obj->IsJSObject()) {
+    HeapIterator iterator(heap, HeapIterator::kFilterUnreachable);
+    // Get the constructor function for context extension and arguments array.
+    Object* arguments_fun = isolate->sloppy_arguments_map()->GetConstructor();
+    HeapObject* heap_obj;
+    while ((heap_obj = iterator.next())) {
+      if (!heap_obj->IsJSObject()) continue;
       JSObject* obj = JSObject::cast(heap_obj);
-      if (obj->map()->GetConstructor() == constructor) {
-        // Valid reference found add to instance array if supplied an update
-        // count.
-        if (instances != NULL && count < instances_size) {
-          instances->set(count, obj);
-        }
-        count++;
+      if (obj->IsJSContextExtensionObject()) continue;
+      if (obj->map()->GetConstructor() == arguments_fun) continue;
+      if (!obj->ReferencesObject(*target)) continue;
+      // Check filter if supplied. This is normally used to avoid
+      // references from mirror objects.
+      if (!filter->IsUndefined() &&
+          obj->HasInPrototypeChain(isolate, *filter)) {
+        continue;
+      }
+      if (obj->IsJSGlobalObject()) {
+        obj = JSGlobalObject::cast(obj)->global_proxy();
       }
+      instances.Add(Handle<JSObject>(obj));
+      if (instances.length() == max_references) break;
+    }
+    // Iterate the rest of the heap to satisfy HeapIterator constraints.
+    while (iterator.next()) {
     }
   }
 
-  // Return the number of referencing objects found.
-  return count;
+  Handle<FixedArray> result;
+  if (instances.length() == 1 && instances.last().is_identical_to(target)) {
+    // Check for circular reference only. This can happen when the object is
+    // only referenced from mirrors and has a circular reference in which case
+    // the object is not really alive and would have been garbage collected if
+    // not referenced from the mirror.
+    result = isolate->factory()->empty_fixed_array();
+  } else {
+    result = isolate->factory()->NewFixedArray(instances.length());
+    for (int i = 0; i < instances.length(); ++i) result->set(i, *instances[i]);
+  }
+  return *isolate->factory()->NewJSArrayWithElements(result);
 }
 
 
@@ -1519,40 +1424,31 @@ static int DebugConstructedBy(HeapIterator* iterator, JSFunction* constructor,
 RUNTIME_FUNCTION(Runtime_DebugConstructedBy) {
   HandleScope scope(isolate);
   DCHECK(args.length() == 2);
-
-
-  // Check parameters.
   CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, 0);
   CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
   RUNTIME_ASSERT(max_references >= 0);
 
-  // Get the number of referencing objects.
-  int count;
-  // First perform a full GC in order to avoid dead objects and to make the heap
-  // iterable.
+  List<Handle<JSObject> > instances;
   Heap* heap = isolate->heap();
-  heap->CollectAllGarbage(Heap::kMakeHeapIterableMask, "%DebugConstructedBy");
-  {
-    HeapIterator heap_iterator(heap);
-    count = DebugConstructedBy(&heap_iterator, *constructor, max_references,
-                               NULL, 0);
-  }
-
-  // Allocate an array to hold the result.
-  Handle<FixedArray> instances = isolate->factory()->NewFixedArray(count);
-
-  // Fill the referencing objects.
   {
-    HeapIterator heap_iterator2(heap);
-    count = DebugConstructedBy(&heap_iterator2, *constructor, max_references,
-                               *instances, count);
+    HeapIterator iterator(heap, HeapIterator::kFilterUnreachable);
+    HeapObject* heap_obj;
+    while ((heap_obj = iterator.next())) {
+      if (!heap_obj->IsJSObject()) continue;
+      JSObject* obj = JSObject::cast(heap_obj);
+      if (obj->map()->GetConstructor() != *constructor) continue;
+      instances.Add(Handle<JSObject>(obj));
+      if (instances.length() == max_references) break;
+    }
+    // Iterate the rest of the heap to satisfy HeapIterator constraints.
+    while (iterator.next()) {
+    }
   }
 
-  // Return result as JS array.
-  Handle<JSFunction> array_function = isolate->array_function();
-  Handle<JSObject> result = isolate->factory()->NewJSObject(array_function);
-  JSArray::SetContent(Handle<JSArray>::cast(result), instances);
-  return *result;
+  Handle<FixedArray> result =
+      isolate->factory()->NewFixedArray(instances.length());
+  for (int i = 0; i < instances.length(); ++i) result->set(i, *instances[i]);
+  return *isolate->factory()->NewJSArrayWithElements(result);
 }
 
 
index 0ec4842..b52980a 100644 (file)
 namespace v8 {
 namespace internal {
 
-
-static int FindSharedFunctionInfosForScript(HeapIterator* iterator,
-                                            Script* script,
-                                            FixedArray* buffer) {
-  DisallowHeapAllocation no_allocation;
-  int counter = 0;
-  int buffer_size = buffer->length();
-  for (HeapObject* obj = iterator->next(); obj != NULL;
-       obj = iterator->next()) {
-    DCHECK(obj != NULL);
-    if (!obj->IsSharedFunctionInfo()) {
-      continue;
-    }
-    SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
-    if (shared->script() != script) {
-      continue;
-    }
-    if (counter < buffer_size) {
-      buffer->set(counter, shared);
-    }
-    counter++;
-  }
-  return counter;
-}
-
-
 // For a script finds all SharedFunctionInfo's in the heap that points
 // to this script. Returns JSArray of SharedFunctionInfo wrapped
 // in OpaqueReferences.
@@ -53,32 +27,29 @@ RUNTIME_FUNCTION(Runtime_LiveEditFindSharedFunctionInfosForScript) {
   RUNTIME_ASSERT(script_value->value()->IsScript());
   Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
 
-  const int kBufferSize = 32;
-
-  Handle<FixedArray> array;
-  array = isolate->factory()->NewFixedArray(kBufferSize);
-  int number;
+  List<Handle<SharedFunctionInfo> > found;
   Heap* heap = isolate->heap();
   {
-    HeapIterator heap_iterator(heap);
-    Script* scr = *script;
-    FixedArray* arr = *array;
-    number = FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
-  }
-  if (number > kBufferSize) {
-    array = isolate->factory()->NewFixedArray(number);
-    HeapIterator heap_iterator(heap);
-    Script* scr = *script;
-    FixedArray* arr = *array;
-    FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
+    HeapIterator iterator(heap);
+    HeapObject* heap_obj;
+    while ((heap_obj = iterator.next())) {
+      if (!heap_obj->IsSharedFunctionInfo()) continue;
+      SharedFunctionInfo* shared = SharedFunctionInfo::cast(heap_obj);
+      if (shared->script() != *script) continue;
+      found.Add(Handle<SharedFunctionInfo>(shared));
+    }
   }
 
-  Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
-  result->set_length(Smi::FromInt(number));
-
-  LiveEdit::WrapSharedFunctionInfos(result);
-
-  return *result;
+  Handle<FixedArray> result = isolate->factory()->NewFixedArray(found.length());
+  for (int i = 0; i < found.length(); ++i) {
+    Handle<SharedFunctionInfo> shared = found[i];
+    SharedInfoWrapper info_wrapper = SharedInfoWrapper::Create(isolate);
+    Handle<String> name(String::cast(shared->name()));
+    info_wrapper.SetProperties(name, shared->start_position(),
+                               shared->end_position(), shared);
+    result->set(i, *info_wrapper.GetJSArray());
+  }
+  return *isolate->factory()->NewJSArrayWithElements(result);
 }
 
 
index 064e4c2..f0c83e0 100644 (file)
@@ -264,17 +264,12 @@ RUNTIME_FUNCTION(Runtime_SetPrototype) {
 
 
 RUNTIME_FUNCTION(Runtime_IsInPrototypeChain) {
-  HandleScope shs(isolate);
+  SealHandleScope shs(isolate);
   DCHECK(args.length() == 2);
   // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
-  CONVERT_ARG_HANDLE_CHECKED(Object, O, 0);
-  CONVERT_ARG_HANDLE_CHECKED(Object, V, 1);
-  PrototypeIterator iter(isolate, V, PrototypeIterator::START_AT_RECEIVER);
-  while (true) {
-    iter.AdvanceIgnoringProxies();
-    if (iter.IsAtEnd()) return isolate->heap()->false_value();
-    if (iter.IsAtEnd(O)) return isolate->heap()->true_value();
-  }
+  CONVERT_ARG_CHECKED(Object, O, 0);
+  CONVERT_ARG_CHECKED(Object, V, 1);
+  return isolate->heap()->ToBoolean(V->HasInPrototypeChain(isolate, O));
 }