Implement verification of context separation.

This adds the --verify-global-context-separation flag which can be used
to verify that no code object embeds pointers to more than one global
context after a full GC. It uses an object visitor that just performs
shallow traversal of the object graph spanned by one code object, and
breaks at points where application objects are encountered. So it will
not trip on cross-context leaks introduced by the application itself.

R=verwaest@chromium.org

Review URL: https://chromiumcodereview.appspot.com/10830049

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@12224 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
mstarzinger@chromium.org 2012-07-30 10:47:04 +00:00
parent cb4840c0e5
commit 76fe67b092
3 changed files with 102 additions and 1 deletions

View File

@ -553,6 +553,8 @@ DEFINE_bool(gc_verbose, false, "print stuff during garbage collection")
DEFINE_bool(heap_stats, false, "report heap statistics before and after GC")
DEFINE_bool(code_stats, false, "report code statistics after GC")
DEFINE_bool(verify_heap, false, "verify heap pointers before and after GC")
DEFINE_bool(verify_global_context_separation, false,
"verify that code holds on to at most one global context after GC")
DEFINE_bool(print_handles, false, "report handles after GC")
DEFINE_bool(print_global_handles, false, "report global handles after GC")

View File

@ -223,6 +223,99 @@ static void VerifyEvacuation(Heap* heap) {
VerifyEvacuationVisitor visitor;
heap->IterateStrongRoots(&visitor, VISIT_ALL);
}
class VerifyGlobalContextSeparationVisitor: public ObjectVisitor {
public:
VerifyGlobalContextSeparationVisitor() : current_global_context_(NULL) {}
void VisitPointers(Object** start, Object** end) {
for (Object** current = start; current < end; current++) {
if ((*current)->IsHeapObject()) {
HeapObject* object = HeapObject::cast(*current);
if (object->IsString()) continue;
switch (object->map()->instance_type()) {
case JS_FUNCTION_TYPE:
CheckContext(JSFunction::cast(object)->context());
break;
case JS_GLOBAL_PROXY_TYPE:
CheckContext(JSGlobalProxy::cast(object)->context());
break;
case JS_GLOBAL_OBJECT_TYPE:
case JS_BUILTINS_OBJECT_TYPE:
CheckContext(GlobalObject::cast(object)->global_context());
break;
case JS_ARRAY_TYPE:
case JS_DATE_TYPE:
case JS_OBJECT_TYPE:
case JS_REGEXP_TYPE:
VisitPointer(HeapObject::RawField(object, JSObject::kMapOffset));
break;
case MAP_TYPE:
VisitPointer(HeapObject::RawField(object, Map::kPrototypeOffset));
VisitPointer(HeapObject::RawField(object, Map::kConstructorOffset));
break;
case FIXED_ARRAY_TYPE:
if (object->IsContext()) {
CheckContext(object);
} else {
FixedArray* array = FixedArray::cast(object);
int length = array->length();
// Set array length to zero to prevent cycles while iterating
// over array bodies, this is easier than intrusive marking.
array->set_length(0);
array->IterateBody(
FIXED_ARRAY_TYPE, FixedArray::SizeFor(length), this);
array->set_length(length);
}
break;
case JS_GLOBAL_PROPERTY_CELL_TYPE:
case JS_PROXY_TYPE:
case JS_VALUE_TYPE:
case TYPE_FEEDBACK_INFO_TYPE:
object->Iterate(this);
break;
case ACCESSOR_INFO_TYPE:
case BYTE_ARRAY_TYPE:
case CALL_HANDLER_INFO_TYPE:
case CODE_TYPE:
case FIXED_DOUBLE_ARRAY_TYPE:
case HEAP_NUMBER_TYPE:
case INTERCEPTOR_INFO_TYPE:
case ODDBALL_TYPE:
case SCRIPT_TYPE:
case SHARED_FUNCTION_INFO_TYPE:
break;
default:
UNREACHABLE();
}
}
}
}
private:
void CheckContext(Object* context) {
if (!context->IsContext()) return;
Context* global_context = Context::cast(context)->global_context();
if (current_global_context_ == NULL) {
current_global_context_ = global_context;
} else {
CHECK_EQ(current_global_context_, global_context);
}
}
Context* current_global_context_;
};
static void VerifyGlobalContextSeparation(Heap* heap) {
HeapObjectIterator it(heap->code_space());
for (Object* object = it.Next(); object != NULL; object = it.Next()) {
VerifyGlobalContextSeparationVisitor visitor;
Code::cast(object)->CodeIterateBody(&visitor);
}
}
#endif
@ -296,6 +389,12 @@ void MarkCompactCollector::CollectGarbage() {
if (!FLAG_collect_maps) ReattachInitialMaps();
#ifdef DEBUG
if (FLAG_verify_global_context_separation) {
VerifyGlobalContextSeparation(heap_);
}
#endif
Finish();
tracer_ = NULL;

View File

@ -822,7 +822,7 @@ void SharedFunctionInfo::SharedFunctionInfoPrint(FILE* out) {
void JSGlobalProxy::JSGlobalProxyPrint(FILE* out) {
PrintF(out, "global_proxy");
PrintF(out, "global_proxy ");
JSObjectPrint(out);
PrintF(out, "context : ");
context()->ShortPrint(out);