Make JSFunction::BodyDescriptor the only single place that knows how to iterate JSFunction's body.

The body descriptor supports different visiting policies: it could visit or skip
the code entry and it could visit or skip next function field.

BUG=v8:4531
LOG=Y

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

Cr-Commit-Position: refs/heads/master@{#31915}
This commit is contained in:
ishell 2015-11-10 03:46:13 -08:00 committed by Commit bot
parent 1e2770123b
commit 8e09ee1dba
7 changed files with 142 additions and 87 deletions

View File

@ -63,7 +63,11 @@ void StaticNewSpaceVisitor<StaticVisitor>::Initialize() {
table_.Register(kVisitSeqTwoByteString, &VisitSeqTwoByteString);
table_.Register(kVisitJSFunction, &VisitJSFunction);
// Don't visit code entry. We are using this visitor only during scavenges.
table_.Register(
kVisitJSFunction,
&FlexibleBodyVisitor<StaticVisitor, JSFunction::BodyDescriptorWeakCode,
int>::Visit);
table_.Register(kVisitJSArrayBuffer, &VisitJSArrayBuffer);
@ -507,14 +511,14 @@ void StaticMarkingVisitor<StaticVisitor>::VisitJSFunction(Map* map,
VisitSharedFunctionInfoWeakCode(heap, shared);
}
// Treat the reference to the code object weakly.
VisitJSFunctionWeakCode(heap, object);
VisitJSFunctionWeakCode(map, object);
return;
} else {
// Visit all unoptimized code objects to prevent flushing them.
StaticVisitor::MarkObject(heap, function->shared()->code());
}
}
VisitJSFunctionStrongCode(heap, object);
VisitJSFunctionStrongCode(map, object);
}
@ -801,42 +805,20 @@ void StaticMarkingVisitor<StaticVisitor>::VisitSharedFunctionInfoWeakCode(
template <typename StaticVisitor>
void StaticMarkingVisitor<StaticVisitor>::VisitJSFunctionStrongCode(
Heap* heap, HeapObject* object) {
Object** start_slot =
HeapObject::RawField(object, JSFunction::kPropertiesOffset);
Object** end_slot =
HeapObject::RawField(object, JSFunction::kCodeEntryOffset);
StaticVisitor::VisitPointers(heap, object, start_slot, end_slot);
VisitCodeEntry(heap, object,
object->address() + JSFunction::kCodeEntryOffset);
STATIC_ASSERT(JSFunction::kCodeEntryOffset + kPointerSize ==
JSFunction::kPrototypeOrInitialMapOffset);
start_slot =
HeapObject::RawField(object, JSFunction::kPrototypeOrInitialMapOffset);
end_slot = HeapObject::RawField(object, JSFunction::kNonWeakFieldsEndOffset);
StaticVisitor::VisitPointers(heap, object, start_slot, end_slot);
Map* map, HeapObject* object) {
typedef FlexibleBodyVisitor<StaticVisitor,
JSFunction::BodyDescriptorStrongCode,
void> JSFunctionStrongCodeBodyVisitor;
JSFunctionStrongCodeBodyVisitor::Visit(map, object);
}
template <typename StaticVisitor>
void StaticMarkingVisitor<StaticVisitor>::VisitJSFunctionWeakCode(
Heap* heap, HeapObject* object) {
Object** start_slot =
HeapObject::RawField(object, JSFunction::kPropertiesOffset);
Object** end_slot =
HeapObject::RawField(object, JSFunction::kCodeEntryOffset);
StaticVisitor::VisitPointers(heap, object, start_slot, end_slot);
// Skip visiting kCodeEntryOffset as it is treated weakly here.
STATIC_ASSERT(JSFunction::kCodeEntryOffset + kPointerSize ==
JSFunction::kPrototypeOrInitialMapOffset);
start_slot =
HeapObject::RawField(object, JSFunction::kPrototypeOrInitialMapOffset);
end_slot = HeapObject::RawField(object, JSFunction::kNonWeakFieldsEndOffset);
StaticVisitor::VisitPointers(heap, object, start_slot, end_slot);
Map* map, HeapObject* object) {
typedef FlexibleBodyVisitor<StaticVisitor, JSFunction::BodyDescriptorWeakCode,
void> JSFunctionWeakCodeBodyVisitor;
JSFunctionWeakCodeBodyVisitor::Visit(map, object);
}

View File

@ -238,8 +238,7 @@ void HeapObject::IterateBody(InstanceType type, int object_size,
JSArrayBuffer::JSArrayBufferIterateBody(this, v);
break;
case JS_FUNCTION_TYPE:
reinterpret_cast<JSFunction*>(this)
->JSFunctionIterateBody(object_size, v);
JSFunction::BodyDescriptor::IterateBody(this, object_size, v);
break;
case ODDBALL_TYPE:
Oddball::BodyDescriptor::IterateBody(this, v);

View File

@ -251,22 +251,15 @@ class StaticNewSpaceVisitor : public StaticVisitorBase {
for (Object** p = start; p < end; p++) StaticVisitor::VisitPointer(heap, p);
}
private:
INLINE(static int VisitJSFunction(Map* map, HeapObject* object)) {
Heap* heap = map->GetHeap();
VisitPointers(heap, object,
HeapObject::RawField(object, JSFunction::kPropertiesOffset),
HeapObject::RawField(object, JSFunction::kCodeEntryOffset));
// Don't visit code entry. We are using this visitor only during scavenges.
VisitPointers(
heap, object, HeapObject::RawField(
object, JSFunction::kCodeEntryOffset + kPointerSize),
HeapObject::RawField(object, JSFunction::kNonWeakFieldsEndOffset));
return JSFunction::kSize;
// Although we are using the JSFunction body descriptor which does not
// visit the code entry, compiler wants it to be accessible.
// See JSFunction::BodyDescriptorImpl.
INLINE(static void VisitCodeEntry(Heap* heap, HeapObject* object,
Address entry_address)) {
UNREACHABLE();
}
private:
INLINE(static int VisitByteArray(Map* map, HeapObject* object)) {
return reinterpret_cast<ByteArray*>(object)->ByteArraySize();
}
@ -405,8 +398,8 @@ class StaticMarkingVisitor : public StaticVisitorBase {
// references to code objects either strongly or weakly.
static void VisitSharedFunctionInfoStrongCode(Heap* heap, HeapObject* object);
static void VisitSharedFunctionInfoWeakCode(Heap* heap, HeapObject* object);
static void VisitJSFunctionStrongCode(Heap* heap, HeapObject* object);
static void VisitJSFunctionWeakCode(Heap* heap, HeapObject* object);
static void VisitJSFunctionStrongCode(Map* map, HeapObject* object);
static void VisitJSFunctionWeakCode(Map* map, HeapObject* object);
class DataObjectVisitor {
public:

View File

@ -7914,8 +7914,7 @@ void ExternalTwoByteString::ExternalTwoByteStringIterateBody() {
void BodyDescriptorBase::IterateBodyImpl(HeapObject* obj, int start_offset,
int end_offset, ObjectVisitor* v) {
if (!FLAG_unbox_double_fields || obj->map()->HasFastPointerLayout()) {
v->VisitPointers(HeapObject::RawField(obj, start_offset),
HeapObject::RawField(obj, end_offset));
IteratePointers(obj, start_offset, end_offset, v);
} else {
DCHECK(FLAG_unbox_double_fields);
DCHECK(IsAligned(start_offset, kPointerSize) &&
@ -7926,8 +7925,7 @@ void BodyDescriptorBase::IterateBodyImpl(HeapObject* obj, int start_offset,
for (int offset = start_offset; offset < end_offset;) {
int end_of_region_offset;
if (helper.IsTagged(offset, end_offset, &end_of_region_offset)) {
v->VisitPointers(HeapObject::RawField(obj, offset),
HeapObject::RawField(obj, end_of_region_offset));
IteratePointers(obj, offset, end_of_region_offset, v);
}
offset = end_of_region_offset;
}
@ -7936,13 +7934,10 @@ void BodyDescriptorBase::IterateBodyImpl(HeapObject* obj, int start_offset,
template <typename StaticVisitor>
void BodyDescriptorBase::IterateBodyImpl(HeapObject* obj, int start_offset,
int end_offset) {
Heap* heap = obj->GetHeap();
void BodyDescriptorBase::IterateBodyImpl(Heap* heap, HeapObject* obj,
int start_offset, int end_offset) {
if (!FLAG_unbox_double_fields || obj->map()->HasFastPointerLayout()) {
StaticVisitor::VisitPointers(heap, obj,
HeapObject::RawField(obj, start_offset),
HeapObject::RawField(obj, end_offset));
IteratePointers<StaticVisitor>(heap, obj, start_offset, end_offset);
} else {
DCHECK(FLAG_unbox_double_fields);
DCHECK(IsAligned(start_offset, kPointerSize) &&
@ -7953,9 +7948,7 @@ void BodyDescriptorBase::IterateBodyImpl(HeapObject* obj, int start_offset,
for (int offset = start_offset; offset < end_offset;) {
int end_of_region_offset;
if (helper.IsTagged(offset, end_offset, &end_of_region_offset)) {
StaticVisitor::VisitPointers(
heap, obj, HeapObject::RawField(obj, offset),
HeapObject::RawField(obj, end_of_region_offset));
IteratePointers<StaticVisitor>(heap, obj, offset, end_of_region_offset);
}
offset = end_of_region_offset;
}
@ -7963,6 +7956,75 @@ void BodyDescriptorBase::IterateBodyImpl(HeapObject* obj, int start_offset,
}
void BodyDescriptorBase::IteratePointers(HeapObject* obj, int start_offset,
int end_offset, ObjectVisitor* v) {
v->VisitPointers(HeapObject::RawField(obj, start_offset),
HeapObject::RawField(obj, end_offset));
}
template <typename StaticVisitor>
void BodyDescriptorBase::IteratePointers(Heap* heap, HeapObject* obj,
int start_offset, int end_offset) {
StaticVisitor::VisitPointers(heap, obj,
HeapObject::RawField(obj, start_offset),
HeapObject::RawField(obj, end_offset));
}
// Iterates the function object according to the visiting policy.
template <JSFunction::BodyVisitingPolicy body_visiting_policy>
class JSFunction::BodyDescriptorImpl : public BodyDescriptorBase {
public:
STATIC_ASSERT(kNonWeakFieldsEndOffset == kCodeEntryOffset);
STATIC_ASSERT(kCodeEntryOffset + kPointerSize == kNextFunctionLinkOffset);
STATIC_ASSERT(kNextFunctionLinkOffset + kPointerSize == kSize);
static inline void IterateBody(HeapObject* obj, int object_size,
ObjectVisitor* v) {
IteratePointers(obj, kPropertiesOffset, kNonWeakFieldsEndOffset, v);
if (body_visiting_policy & kVisitCodeEntry) {
v->VisitCodeEntry(obj->address() + kCodeEntryOffset);
}
if (body_visiting_policy & kVisitNextFunction) {
IteratePointers(obj, kNextFunctionLinkOffset, kSize, v);
}
// TODO(ishell): v8:4531, fix when JFunctions are allowed to have in-object
// properties
// IterateBodyImpl(obj, kSize, object_size, v);
}
template <typename StaticVisitor>
static inline void IterateBody(HeapObject* obj, int object_size) {
Heap* heap = obj->GetHeap();
IteratePointers<StaticVisitor>(heap, obj, kPropertiesOffset,
kNonWeakFieldsEndOffset);
if (body_visiting_policy & kVisitCodeEntry) {
StaticVisitor::VisitCodeEntry(heap, obj,
obj->address() + kCodeEntryOffset);
}
if (body_visiting_policy & kVisitNextFunction) {
IteratePointers<StaticVisitor>(heap, obj, kNextFunctionLinkOffset, kSize);
}
// TODO(ishell): v8:4531, fix when JFunctions are allowed to have in-object
// properties
// IterateBodyImpl<StaticVisitor>(heap, obj, kSize, object_size);
}
static inline int SizeOf(Map* map, HeapObject* object) {
// TODO(ishell): v8:4531, fix when JFunctions are allowed to have in-object
// properties
return JSFunction::kSize;
}
};
template<class Derived, class TableType>
Object* OrderedHashTableIterator<Derived, TableType>::CurrentKey() {
TableType* table(TableType::cast(this->table()));

View File

@ -10980,15 +10980,6 @@ bool Map::EquivalentToForNormalization(Map* other,
}
void JSFunction::JSFunctionIterateBody(int object_size, ObjectVisitor* v) {
// Iterate over all fields in the body but take care in dealing with
// the code entry.
IteratePointers(v, kPropertiesOffset, kCodeEntryOffset);
v->VisitCodeEntry(this->address() + kCodeEntryOffset);
IteratePointers(v, kCodeEntryOffset + kPointerSize, object_size);
}
bool JSFunction::Inlines(SharedFunctionInfo* candidate) {
DisallowHeapAllocation no_gc;
if (shared() == candidate) return true;

View File

@ -1644,8 +1644,15 @@ class BodyDescriptorBase {
int end_offset, ObjectVisitor* v);
template <typename StaticVisitor>
static inline void IterateBodyImpl(HeapObject* obj, int start_offset,
int end_offset);
static inline void IterateBodyImpl(Heap* heap, HeapObject* obj,
int start_offset, int end_offset);
static inline void IteratePointers(HeapObject* obj, int start_offset,
int end_offset, ObjectVisitor* v);
template <typename StaticVisitor>
static inline void IteratePointers(Heap* heap, HeapObject* obj,
int start_offset, int end_offset);
};
@ -1665,7 +1672,8 @@ class FixedBodyDescriptor : public BodyDescriptorBase {
template <typename StaticVisitor>
static inline void IterateBody(HeapObject* obj) {
IterateBodyImpl<StaticVisitor>(obj, start_offset, end_offset);
Heap* heap = obj->GetHeap();
IterateBodyImpl<StaticVisitor>(heap, obj, start_offset, end_offset);
}
};
@ -1685,7 +1693,8 @@ class FlexibleBodyDescriptorBase : public BodyDescriptorBase {
template <typename StaticVisitor>
static inline void IterateBody(HeapObject* obj, int object_size) {
IterateBodyImpl<StaticVisitor>(obj, start_offset, object_size);
Heap* heap = obj->GetHeap();
IterateBodyImpl<StaticVisitor>(heap, obj, start_offset, object_size);
}
};
@ -7409,9 +7418,26 @@ class JSFunction: public JSObject {
int* instance_size,
int* in_object_properties);
// Iterates the objects, including code objects indirectly referenced
// through pointers to the first instruction in the code object.
void JSFunctionIterateBody(int object_size, ObjectVisitor* v);
// Visiting policy flags define whether the code entry or next function
// should be visited or not.
enum BodyVisitingPolicy {
kVisitCodeEntry = 1 << 0,
kVisitNextFunction = 1 << 1,
kSkipCodeEntryAndNextFunction = 0,
kVisitCodeEntryAndNextFunction = kVisitCodeEntry | kVisitNextFunction
};
// Iterates the function object according to the visiting policy.
template <BodyVisitingPolicy>
class BodyDescriptorImpl;
// Visit the whole object.
typedef BodyDescriptorImpl<kVisitCodeEntryAndNextFunction> BodyDescriptor;
// Don't visit next function.
typedef BodyDescriptorImpl<kVisitCodeEntry> BodyDescriptorStrongCode;
typedef BodyDescriptorImpl<kSkipCodeEntryAndNextFunction>
BodyDescriptorWeakCode;
// Dispatched behavior.
DECLARE_PRINTER(JSFunction)
@ -7429,15 +7455,14 @@ class JSFunction: public JSObject {
// Layout descriptors. The last property (from kNonWeakFieldsEndOffset to
// kSize) is weak and has special handling during garbage collection.
static const int kCodeEntryOffset = JSObject::kHeaderSize;
static const int kPrototypeOrInitialMapOffset =
kCodeEntryOffset + kPointerSize;
static const int kPrototypeOrInitialMapOffset = JSObject::kHeaderSize;
static const int kSharedFunctionInfoOffset =
kPrototypeOrInitialMapOffset + kPointerSize;
static const int kContextOffset = kSharedFunctionInfoOffset + kPointerSize;
static const int kLiteralsOffset = kContextOffset + kPointerSize;
static const int kNonWeakFieldsEndOffset = kLiteralsOffset + kPointerSize;
static const int kNextFunctionLinkOffset = kNonWeakFieldsEndOffset;
static const int kCodeEntryOffset = kNonWeakFieldsEndOffset;
static const int kNextFunctionLinkOffset = kCodeEntryOffset + kPointerSize;
static const int kSize = kNextFunctionLinkOffset + kPointerSize;
private:

View File

@ -1158,8 +1158,11 @@ void V8HeapExplorer::ExtractJSObjectReferences(
SetWeakReference(js_fun, entry,
"next_function_link", js_fun->next_function_link(),
JSFunction::kNextFunctionLinkOffset);
STATIC_ASSERT(JSFunction::kNextFunctionLinkOffset
== JSFunction::kNonWeakFieldsEndOffset);
// Ensure no new weak references appeared in JSFunction.
STATIC_ASSERT(JSFunction::kCodeEntryOffset ==
JSFunction::kNonWeakFieldsEndOffset);
STATIC_ASSERT(JSFunction::kCodeEntryOffset + kPointerSize ==
JSFunction::kNextFunctionLinkOffset);
STATIC_ASSERT(JSFunction::kNextFunctionLinkOffset + kPointerSize
== JSFunction::kSize);
} else if (obj->IsJSGlobalObject()) {