Commit fe4d8e28 authored by yangguo's avatar yangguo Committed by Commit bot

Debugger: remove duplicate heap iterations.

R=mlippautz@chromium.org

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

Cr-Commit-Position: refs/heads/master@{#30162}
parent 4b340c89
......@@ -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.
......
......@@ -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);
......
......@@ -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()) {
......
......@@ -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();
......
......@@ -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);
}
......
......@@ -15,32 +15,6 @@
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);
}
......
......@@ -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));
}
......
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