Reland "[heap-stats] Fix heap-stats with ptr-cage"
This is a reland of 9ae463bc43
- Don't run the heap stats during bootstrapping
Original change's description:
> [heap-stats] Fix heap-stats with ptr-cage
>
> - Heap-stats was trying to load the map without explicitly passing in
> the PtrComprBase causing failures with Code objects in external code
> space
> - Extend the debugPrint.js tests to run with some more debugging and
> testing flags to prevent future regressions
>
> Change-Id: I1f0d03cb31480f316fe533b507ff98fe3befbe8e
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3432386
> Reviewed-by: Igor Sheludko <ishell@chromium.org>
> Auto-Submit: Camillo Bruni <cbruni@chromium.org>
> Reviewed-by: Dominik Inführ <dinfuehr@chromium.org>
> Commit-Queue: Dominik Inführ <dinfuehr@chromium.org>
> Cr-Commit-Position: refs/heads/main@{#78919}
Bug: chromium:1297436
Change-Id: Ib42ae7b8c5f4a427abbce633a1b3ac36ad32994b
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3437046
Reviewed-by: Dominik Inführ <dinfuehr@chromium.org>
Commit-Queue: Camillo Bruni <cbruni@chromium.org>
Cr-Commit-Position: refs/heads/main@{#79127}
This commit is contained in:
parent
a944e66b05
commit
148d9853e0
@ -2289,28 +2289,29 @@ void MarkCompactCollector::ProcessTopOptimizedFrame(ObjectVisitor* visitor,
|
||||
}
|
||||
|
||||
void MarkCompactCollector::RecordObjectStats() {
|
||||
if (V8_UNLIKELY(TracingFlags::is_gc_stats_enabled())) {
|
||||
heap()->CreateObjectStats();
|
||||
ObjectStatsCollector collector(heap(), heap()->live_object_stats_.get(),
|
||||
heap()->dead_object_stats_.get());
|
||||
collector.Collect();
|
||||
if (V8_UNLIKELY(TracingFlags::gc_stats.load(std::memory_order_relaxed) &
|
||||
v8::tracing::TracingCategoryObserver::ENABLED_BY_TRACING)) {
|
||||
std::stringstream live, dead;
|
||||
heap()->live_object_stats_->Dump(live);
|
||||
heap()->dead_object_stats_->Dump(dead);
|
||||
TRACE_EVENT_INSTANT2(TRACE_DISABLED_BY_DEFAULT("v8.gc_stats"),
|
||||
"V8.GC_Objects_Stats", TRACE_EVENT_SCOPE_THREAD,
|
||||
"live", TRACE_STR_COPY(live.str().c_str()), "dead",
|
||||
TRACE_STR_COPY(dead.str().c_str()));
|
||||
}
|
||||
if (FLAG_trace_gc_object_stats) {
|
||||
heap()->live_object_stats_->PrintJSON("live");
|
||||
heap()->dead_object_stats_->PrintJSON("dead");
|
||||
}
|
||||
heap()->live_object_stats_->CheckpointObjectStats();
|
||||
heap()->dead_object_stats_->ClearObjectStats();
|
||||
if (V8_LIKELY(!TracingFlags::is_gc_stats_enabled())) return;
|
||||
// Cannot run during bootstrapping due to incomplete objects.
|
||||
if (isolate()->bootstrapper()->IsActive()) return;
|
||||
heap()->CreateObjectStats();
|
||||
ObjectStatsCollector collector(heap(), heap()->live_object_stats_.get(),
|
||||
heap()->dead_object_stats_.get());
|
||||
collector.Collect();
|
||||
if (V8_UNLIKELY(TracingFlags::gc_stats.load(std::memory_order_relaxed) &
|
||||
v8::tracing::TracingCategoryObserver::ENABLED_BY_TRACING)) {
|
||||
std::stringstream live, dead;
|
||||
heap()->live_object_stats_->Dump(live);
|
||||
heap()->dead_object_stats_->Dump(dead);
|
||||
TRACE_EVENT_INSTANT2(TRACE_DISABLED_BY_DEFAULT("v8.gc_stats"),
|
||||
"V8.GC_Objects_Stats", TRACE_EVENT_SCOPE_THREAD,
|
||||
"live", TRACE_STR_COPY(live.str().c_str()), "dead",
|
||||
TRACE_STR_COPY(dead.str().c_str()));
|
||||
}
|
||||
if (FLAG_trace_gc_object_stats) {
|
||||
heap()->live_object_stats_->PrintJSON("live");
|
||||
heap()->dead_object_stats_->PrintJSON("dead");
|
||||
}
|
||||
heap()->live_object_stats_->CheckpointObjectStats();
|
||||
heap()->dead_object_stats_->ClearObjectStats();
|
||||
}
|
||||
|
||||
void MarkCompactCollector::MarkLiveObjects() {
|
||||
|
@ -443,6 +443,11 @@ class ObjectStatsCollectorImpl {
|
||||
|
||||
void RecordVirtualArrayBoilerplateDescription(
|
||||
ArrayBoilerplateDescription description);
|
||||
|
||||
PtrComprCageBase cage_base() const {
|
||||
return field_stats_collector_.cage_base();
|
||||
}
|
||||
|
||||
Heap* heap_;
|
||||
ObjectStats* stats_;
|
||||
MarkCompactCollector::NonAtomicMarkingState* marking_state_;
|
||||
@ -488,7 +493,7 @@ void ObjectStatsCollectorImpl::RecordHashTableVirtualObjectStats(
|
||||
|
||||
bool ObjectStatsCollectorImpl::RecordSimpleVirtualObjectStats(
|
||||
HeapObject parent, HeapObject obj, ObjectStats::VirtualInstanceType type) {
|
||||
return RecordVirtualObjectStats(parent, obj, type, obj.Size(),
|
||||
return RecordVirtualObjectStats(parent, obj, type, obj.Size(cage_base()),
|
||||
ObjectStats::kNoOverAllocation, kCheckCow);
|
||||
}
|
||||
|
||||
@ -711,7 +716,8 @@ void ObjectStatsCollectorImpl::RecordVirtualFeedbackVectorDetails(
|
||||
MaybeObject raw_object = vector.Get(slot.WithOffset(i));
|
||||
HeapObject object;
|
||||
if (raw_object->GetHeapObject(&object)) {
|
||||
if (object.IsCell() || object.IsWeakFixedArray()) {
|
||||
if (object.IsCell(cage_base()) ||
|
||||
object.IsWeakFixedArray(cage_base())) {
|
||||
RecordSimpleVirtualObjectStats(
|
||||
vector, object, ObjectStats::FEEDBACK_VECTOR_ENTRY_TYPE);
|
||||
}
|
||||
@ -733,51 +739,55 @@ void ObjectStatsCollectorImpl::RecordVirtualFixedArrayDetails(
|
||||
|
||||
void ObjectStatsCollectorImpl::CollectStatistics(
|
||||
HeapObject obj, Phase phase, CollectFieldStats collect_field_stats) {
|
||||
Map map = obj.map();
|
||||
DisallowGarbageCollection no_gc;
|
||||
Map map = obj.map(cage_base());
|
||||
InstanceType instance_type = map.instance_type();
|
||||
switch (phase) {
|
||||
case kPhase1:
|
||||
if (obj.IsFeedbackVector()) {
|
||||
if (InstanceTypeChecker::IsFeedbackVector(instance_type)) {
|
||||
RecordVirtualFeedbackVectorDetails(FeedbackVector::cast(obj));
|
||||
} else if (obj.IsMap()) {
|
||||
} else if (InstanceTypeChecker::IsMap(instance_type)) {
|
||||
RecordVirtualMapDetails(Map::cast(obj));
|
||||
} else if (obj.IsBytecodeArray()) {
|
||||
} else if (InstanceTypeChecker::IsBytecodeArray(instance_type)) {
|
||||
RecordVirtualBytecodeArrayDetails(BytecodeArray::cast(obj));
|
||||
} else if (obj.IsCode()) {
|
||||
} else if (InstanceTypeChecker::IsCode(instance_type)) {
|
||||
RecordVirtualCodeDetails(Code::cast(obj));
|
||||
} else if (obj.IsFunctionTemplateInfo()) {
|
||||
} else if (InstanceTypeChecker::IsFunctionTemplateInfo(instance_type)) {
|
||||
RecordVirtualFunctionTemplateInfoDetails(
|
||||
FunctionTemplateInfo::cast(obj));
|
||||
} else if (obj.IsJSGlobalObject()) {
|
||||
} else if (InstanceTypeChecker::IsJSGlobalObject(instance_type)) {
|
||||
RecordVirtualJSGlobalObjectDetails(JSGlobalObject::cast(obj));
|
||||
} else if (obj.IsJSObject()) {
|
||||
} else if (InstanceTypeChecker::IsJSObject(instance_type)) {
|
||||
// This phase needs to come after RecordVirtualAllocationSiteDetails
|
||||
// to properly split among boilerplates.
|
||||
RecordVirtualJSObjectDetails(JSObject::cast(obj));
|
||||
} else if (obj.IsSharedFunctionInfo()) {
|
||||
} else if (InstanceTypeChecker::IsSharedFunctionInfo(instance_type)) {
|
||||
RecordVirtualSharedFunctionInfoDetails(SharedFunctionInfo::cast(obj));
|
||||
} else if (obj.IsContext()) {
|
||||
} else if (InstanceTypeChecker::IsContext(instance_type)) {
|
||||
RecordVirtualContext(Context::cast(obj));
|
||||
} else if (obj.IsScript()) {
|
||||
} else if (InstanceTypeChecker::IsScript(instance_type)) {
|
||||
RecordVirtualScriptDetails(Script::cast(obj));
|
||||
} else if (obj.IsArrayBoilerplateDescription()) {
|
||||
} else if (InstanceTypeChecker::IsArrayBoilerplateDescription(
|
||||
instance_type)) {
|
||||
RecordVirtualArrayBoilerplateDescription(
|
||||
ArrayBoilerplateDescription::cast(obj));
|
||||
} else if (obj.IsFixedArrayExact()) {
|
||||
} else if (InstanceTypeChecker::IsFixedArrayExact(instance_type)) {
|
||||
// Has to go last as it triggers too eagerly.
|
||||
RecordVirtualFixedArrayDetails(FixedArray::cast(obj));
|
||||
}
|
||||
break;
|
||||
case kPhase2:
|
||||
if (obj.IsExternalString()) {
|
||||
if (InstanceTypeChecker::IsExternalString(instance_type)) {
|
||||
// This has to be in Phase2 to avoid conflicting with recording Script
|
||||
// sources. We still want to run RecordObjectStats after though.
|
||||
RecordVirtualExternalStringDetails(ExternalString::cast(obj));
|
||||
}
|
||||
size_t over_allocated = ObjectStats::kNoOverAllocation;
|
||||
if (obj.IsJSObject()) {
|
||||
if (InstanceTypeChecker::IsJSObject(instance_type)) {
|
||||
over_allocated = map.instance_size() - map.UsedInstanceSize();
|
||||
}
|
||||
RecordObjectStats(obj, map.instance_type(), obj.Size(), over_allocated);
|
||||
RecordObjectStats(obj, instance_type, obj.Size(cage_base()),
|
||||
over_allocated);
|
||||
if (collect_field_stats == CollectFieldStats::kYes) {
|
||||
field_stats_collector_.RecordStats(obj);
|
||||
}
|
||||
@ -788,7 +798,7 @@ void ObjectStatsCollectorImpl::CollectStatistics(
|
||||
void ObjectStatsCollectorImpl::CollectGlobalStatistics() {
|
||||
// Iterate boilerplates first to disambiguate them from regular JS objects.
|
||||
Object list = heap_->allocation_sites_list();
|
||||
while (list.IsAllocationSite()) {
|
||||
while (list.IsAllocationSite(cage_base())) {
|
||||
AllocationSite site = AllocationSite::cast(list);
|
||||
RecordVirtualAllocationSiteDetails(site);
|
||||
list = site.weak_next();
|
||||
@ -829,7 +839,7 @@ bool ObjectStatsCollectorImpl::CanRecordFixedArray(FixedArrayBase array) {
|
||||
}
|
||||
|
||||
bool ObjectStatsCollectorImpl::IsCowArray(FixedArrayBase array) {
|
||||
return array.map() == ReadOnlyRoots(heap_).fixed_cow_array_map();
|
||||
return array.map(cage_base()) == ReadOnlyRoots(heap_).fixed_cow_array_map();
|
||||
}
|
||||
|
||||
bool ObjectStatsCollectorImpl::SameLiveness(HeapObject obj1, HeapObject obj2) {
|
||||
@ -868,7 +878,7 @@ void ObjectStatsCollectorImpl::RecordVirtualMapDetails(Map map) {
|
||||
// This will be logged as MAP_TYPE in Phase2.
|
||||
}
|
||||
|
||||
DescriptorArray array = map.instance_descriptors(isolate());
|
||||
DescriptorArray array = map.instance_descriptors(cage_base());
|
||||
if (map.owns_descriptors() &&
|
||||
array != ReadOnlyRoots(heap_).empty_descriptor_array()) {
|
||||
// Generally DescriptorArrays have their own instance type already
|
||||
@ -891,10 +901,10 @@ void ObjectStatsCollectorImpl::RecordVirtualMapDetails(Map map) {
|
||||
}
|
||||
|
||||
if (map.is_prototype_map()) {
|
||||
if (map.prototype_info().IsPrototypeInfo()) {
|
||||
if (map.prototype_info().IsPrototypeInfo(cage_base())) {
|
||||
PrototypeInfo info = PrototypeInfo::cast(map.prototype_info());
|
||||
Object users = info.prototype_users();
|
||||
if (users.IsWeakFixedArray()) {
|
||||
if (users.IsWeakFixedArray(cage_base())) {
|
||||
RecordSimpleVirtualObjectStats(map, WeakArrayList::cast(users),
|
||||
ObjectStats::PROTOTYPE_USERS_TYPE);
|
||||
}
|
||||
@ -909,7 +919,7 @@ void ObjectStatsCollectorImpl::RecordVirtualScriptDetails(Script script) {
|
||||
|
||||
// Log the size of external source code.
|
||||
Object raw_source = script.source();
|
||||
if (raw_source.IsExternalString()) {
|
||||
if (raw_source.IsExternalString(cage_base())) {
|
||||
// The contents of external strings aren't on the heap, so we have to record
|
||||
// them manually. The on-heap String object is recorded indepentendely in
|
||||
// the normal pass.
|
||||
@ -922,7 +932,7 @@ void ObjectStatsCollectorImpl::RecordVirtualScriptDetails(Script script) {
|
||||
? ObjectStats::SCRIPT_SOURCE_EXTERNAL_ONE_BYTE_TYPE
|
||||
: ObjectStats::SCRIPT_SOURCE_EXTERNAL_TWO_BYTE_TYPE,
|
||||
off_heap_size);
|
||||
} else if (raw_source.IsString()) {
|
||||
} else if (raw_source.IsString(cage_base())) {
|
||||
String source = String::cast(raw_source);
|
||||
RecordSimpleVirtualObjectStats(
|
||||
script, source,
|
||||
@ -940,7 +950,7 @@ void ObjectStatsCollectorImpl::RecordVirtualExternalStringDetails(
|
||||
size_t off_heap_size = string.ExternalPayloadSize();
|
||||
RecordExternalResourceStats(
|
||||
resource,
|
||||
string.IsOneByteRepresentation()
|
||||
string.IsOneByteRepresentation(cage_base())
|
||||
? ObjectStats::STRING_EXTERNAL_RESOURCE_ONE_BYTE_TYPE
|
||||
: ObjectStats::STRING_EXTERNAL_RESOURCE_TWO_BYTE_TYPE,
|
||||
off_heap_size);
|
||||
@ -967,7 +977,7 @@ void ObjectStatsCollectorImpl::
|
||||
HeapObject parent, HeapObject object,
|
||||
ObjectStats::VirtualInstanceType type) {
|
||||
if (!RecordSimpleVirtualObjectStats(parent, object, type)) return;
|
||||
if (object.IsFixedArrayExact()) {
|
||||
if (object.IsFixedArrayExact(cage_base())) {
|
||||
FixedArray array = FixedArray::cast(object);
|
||||
for (int i = 0; i < array.length(); i++) {
|
||||
Object entry = array.get(i);
|
||||
@ -988,7 +998,7 @@ void ObjectStatsCollectorImpl::RecordVirtualBytecodeArrayDetails(
|
||||
FixedArray constant_pool = FixedArray::cast(bytecode.constant_pool());
|
||||
for (int i = 0; i < constant_pool.length(); i++) {
|
||||
Object entry = constant_pool.get(i);
|
||||
if (entry.IsFixedArrayExact()) {
|
||||
if (entry.IsFixedArrayExact(cage_base())) {
|
||||
RecordVirtualObjectsForConstantPoolOrEmbeddedObjects(
|
||||
constant_pool, HeapObject::cast(entry),
|
||||
ObjectStats::EMBEDDED_OBJECT_TYPE);
|
||||
@ -1041,11 +1051,10 @@ void ObjectStatsCollectorImpl::RecordVirtualCodeDetails(Code code) {
|
||||
}
|
||||
}
|
||||
int const mode_mask = RelocInfo::EmbeddedObjectModeMask();
|
||||
PtrComprCageBase cage_base(heap_->isolate());
|
||||
for (RelocIterator it(code, mode_mask); !it.done(); it.next()) {
|
||||
DCHECK(RelocInfo::IsEmbeddedObjectMode(it.rinfo()->rmode()));
|
||||
Object target = it.rinfo()->target_object(cage_base);
|
||||
if (target.IsFixedArrayExact()) {
|
||||
Object target = it.rinfo()->target_object(cage_base());
|
||||
if (target.IsFixedArrayExact(cage_base())) {
|
||||
RecordVirtualObjectsForConstantPoolOrEmbeddedObjects(
|
||||
code, HeapObject::cast(target), ObjectStats::EMBEDDED_OBJECT_TYPE);
|
||||
}
|
||||
@ -1055,7 +1064,7 @@ void ObjectStatsCollectorImpl::RecordVirtualCodeDetails(Code code) {
|
||||
void ObjectStatsCollectorImpl::RecordVirtualContext(Context context) {
|
||||
if (context.IsNativeContext()) {
|
||||
RecordObjectStats(context, NATIVE_CONTEXT_TYPE, context.Size());
|
||||
if (context.retained_maps().IsWeakArrayList()) {
|
||||
if (context.retained_maps().IsWeakArrayList(cage_base())) {
|
||||
RecordSimpleVirtualObjectStats(
|
||||
context, WeakArrayList::cast(context.retained_maps()),
|
||||
ObjectStats::RETAINED_MAPS_TYPE);
|
||||
|
@ -2,7 +2,10 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Flags: --allow-natives-syntax
|
||||
// Test various debug flags
|
||||
|
||||
// Flags: --allow-natives-syntax --trace-gc-object-stats --gc-global
|
||||
// Flags: --trace-zone-stats --expose-gc --trace-gc
|
||||
|
||||
var largeArray = [];
|
||||
largeArray[0xFFFF00] = 123;
|
||||
@ -25,7 +28,22 @@ function slowSloppyArguments2(a, b) {
|
||||
return arguments;
|
||||
}
|
||||
|
||||
let proto_obj = { fn1() { return 1 } }
|
||||
let obj_with_enum_cache = {
|
||||
__proto__: proto_obj,
|
||||
a: 1,
|
||||
b: 2,
|
||||
c: "c"
|
||||
};
|
||||
|
||||
for (let k in obj_with_enum_cache) {
|
||||
// do something
|
||||
obj_with_enum_cache.a += obj_with_enum_cache.fn1();
|
||||
}
|
||||
|
||||
|
||||
let string_1 = "aasdfasdfasdfasdf asd fa sdf asdf as dfa sdf asd f"
|
||||
let string_2 = "aasdfasdfasdfasdf asd fa sdf UC16\u2028asdf as dfa sdf asd f"
|
||||
var objects = [
|
||||
this,
|
||||
true, false, null, undefined,
|
||||
@ -33,8 +51,10 @@ var objects = [
|
||||
9007199254740991.0, 9007199254740991.0 + 10,
|
||||
-9007199254740992.0, -9007199254740992.0 - 10,
|
||||
Infinity, -Infinity, NaN,
|
||||
"aasdfasdfasdfasdf", "a"+"b",
|
||||
string_1, string_1+"b", string_1.slice(1),
|
||||
string_2, string_2+"b", string_2.slice(1),
|
||||
{}, {1:1}, {a:1}, {1:1, 2:2}, Object.create(null),
|
||||
obj_with_enum_cache,
|
||||
[], [{}, {}], [1, 1, 1], [1.1, 1.1, 1.1, 1.1, 2], largeArray,
|
||||
new Proxy({},{}),
|
||||
new Date(), new String(" a"),
|
||||
@ -53,3 +73,6 @@ var objects = [
|
||||
|
||||
];
|
||||
for (var o of objects) %DebugPrint(o);
|
||||
|
||||
// Trigger some gcs to trigger heap and zone stats
|
||||
for (let i = 0; i <= 4; i++) gc();
|
||||
|
Loading…
Reference in New Issue
Block a user