| Index: src/runtime/runtime-debug.cc
|
| diff --git a/src/runtime/runtime-debug.cc b/src/runtime/runtime-debug.cc
|
| index 97c3ff48a9a6535208c91ceb733e3f7ae3fa5af4..d4acf792b55ab0f4e194319c1bf701bcd049d892 100644
|
| --- a/src/runtime/runtime-debug.cc
|
| +++ b/src/runtime/runtime-debug.cc
|
| @@ -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);
|
| }
|
|
|
|
|
|
|