Commit 0a1a714f authored by yangguo's avatar yangguo Committed by Commit bot

Introduce object visitor to estimate the size of a native context.

This is only an estimate since it counts objects that could be shared,
for example strings, cow arrays, heap numbers, etc.

It however ignores objects that could be shared, but may only be used
by the context to be measured, for example shared function infos,
script objects, scope infos, etc.

R=jochen@chromium.org

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

Cr-Commit-Position: refs/heads/master@{#30029}
parent 1cb27bce
......@@ -822,6 +822,8 @@ source_set("v8_base") {
"src/compiler/zone-pool.h",
"src/compiler.cc",
"src/compiler.h",
"src/context-measure.cc",
"src/context-measure.h",
"src/contexts.cc",
"src/contexts.h",
"src/conversions-inl.h",
......
......@@ -6661,6 +6661,11 @@ class V8_EXPORT Context {
*/
void SetErrorMessageForCodeGenerationFromStrings(Local<String> message);
/**
* Estimate the memory in bytes retained by this context.
*/
size_t EstimatedSize();
/**
* Stack-allocated class which sets the execution context for all
* operations executed within a local scope.
......
......@@ -22,6 +22,7 @@
#include "src/bootstrapper.h"
#include "src/code-stubs.h"
#include "src/compiler.h"
#include "src/context-measure.h"
#include "src/contexts.h"
#include "src/conversions-inl.h"
#include "src/counters.h"
......@@ -5575,6 +5576,12 @@ void Context::SetErrorMessageForCodeGenerationFromStrings(Local<String> error) {
}
size_t Context::EstimatedSize() {
return static_cast<size_t>(
i::ContextMeasure(*Utils::OpenHandle(this)).Size());
}
MaybeLocal<v8::Object> ObjectTemplate::NewInstance(Local<Context> context) {
PREPARE_FOR_EXECUTION(context, "v8::ObjectTemplate::NewInstance()", Object);
auto self = Utils::OpenHandle(this);
......
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/v8.h"
#include "src/context-measure.h"
namespace v8 {
namespace internal {
ContextMeasure::ContextMeasure(Context* context)
: context_(context),
root_index_map_(context->GetIsolate()),
recursion_depth_(0),
count_(0),
size_(0) {
DCHECK(context_->IsNativeContext());
Object* next_link = context_->get(Context::NEXT_CONTEXT_LINK);
MeasureObject(context_);
MeasureDeferredObjects();
context_->set(Context::NEXT_CONTEXT_LINK, next_link);
}
bool ContextMeasure::IsShared(HeapObject* object) {
if (object->IsScript()) return true;
if (object->IsSharedFunctionInfo()) return true;
if (object->IsScopeInfo()) return true;
if (object->IsCode() && !Code::cast(object)->is_optimized_code()) return true;
if (object->IsExecutableAccessorInfo()) return true;
if (object->IsWeakCell()) return true;
return false;
}
void ContextMeasure::MeasureObject(HeapObject* object) {
if (back_reference_map_.Lookup(object).is_valid()) return;
if (root_index_map_.Lookup(object) != RootIndexMap::kInvalidRootIndex) return;
if (IsShared(object)) return;
back_reference_map_.Add(object, BackReference::DummyReference());
recursion_depth_++;
if (recursion_depth_ > kMaxRecursion) {
deferred_objects_.Add(object);
} else {
MeasureAndRecurse(object);
}
recursion_depth_--;
}
void ContextMeasure::MeasureDeferredObjects() {
while (deferred_objects_.length() > 0) {
MeasureAndRecurse(deferred_objects_.RemoveLast());
}
}
void ContextMeasure::MeasureAndRecurse(HeapObject* object) {
int size = object->Size();
count_++;
size_ += size;
Map* map = object->map();
MeasureObject(map);
object->IterateBody(map->instance_type(), size, this);
}
void ContextMeasure::VisitPointers(Object** start, Object** end) {
for (Object** current = start; current < end; current++) {
if ((*current)->IsSmi()) continue;
MeasureObject(HeapObject::cast(*current));
}
}
}
} // namespace v8::internal
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_CONTEXT_MEASURE_H_
#define V8_CONTEXT_MEASURE_H_
#include "src/snapshot/serialize.h"
namespace v8 {
namespace internal {
class ContextMeasure : public ObjectVisitor {
public:
explicit ContextMeasure(Context* context);
int Size() { return size_; }
int Count() { return count_; }
void VisitPointers(Object** start, Object** end);
private:
void MeasureObject(HeapObject* object);
void MeasureDeferredObjects();
void MeasureAndRecurse(HeapObject* object);
bool IsShared(HeapObject* object);
Context* context_;
BackReferenceMap back_reference_map_;
RootIndexMap root_index_map_;
static const int kMaxRecursion = 16;
int recursion_depth_;
List<HeapObject*> deferred_objects_;
int count_;
int size_;
DisallowHeapAllocation no_gc_;
DISALLOW_COPY_AND_ASSIGN(ContextMeasure);
};
}
} // namespace v8::internal
#endif // V8_CONTEXT_MEASURE_H_
......@@ -6,7 +6,6 @@
#define V8_SNAPSHOT_SERIALIZE_H_
#include "src/hashmap.h"
#include "src/heap-profiler.h"
#include "src/isolate.h"
#include "src/snapshot/snapshot-source-sink.h"
......@@ -156,6 +155,8 @@ class BackReference {
ChunkOffsetBits::encode(index));
}
static BackReference DummyReference() { return BackReference(kDummyValue); }
static BackReference Reference(AllocationSpace space, uint32_t chunk_index,
uint32_t chunk_offset) {
DCHECK(IsAligned(chunk_offset, kObjectAlignment));
......@@ -201,6 +202,7 @@ class BackReference {
static const uint32_t kInvalidValue = 0xFFFFFFFF;
static const uint32_t kSourceValue = 0xFFFFFFFE;
static const uint32_t kGlobalProxyValue = 0xFFFFFFFD;
static const uint32_t kDummyValue = 0xFFFFFFFC;
static const int kChunkOffsetSize = kPageSizeBits - kObjectAlignmentBits;
static const int kChunkIndexSize = 32 - kChunkOffsetSize - kSpaceTagSize;
......
......@@ -21827,3 +21827,11 @@ TEST(FutexInterruption) {
"Atomics.futexWait(i32a, 0, 0);");
CHECK(try_catch.HasTerminated());
}
TEST(EstimatedContextSize) {
v8::Isolate* isolate = CcTest::isolate();
v8::HandleScope scope(isolate);
LocalContext env;
CHECK(50000 < env->EstimatedSize());
}
......@@ -31,6 +31,7 @@
#include "src/v8.h"
#include "src/compilation-cache.h"
#include "src/context-measure.h"
#include "src/deoptimizer.h"
#include "src/execution.h"
#include "src/factory.h"
......@@ -6268,3 +6269,30 @@ TEST(SlotsBufferObjectSlotsRemoval) {
FixedArrayBase::kLengthOffset));
delete buffer;
}
TEST(ContextMeasure) {
CcTest::InitializeVM();
v8::HandleScope scope(CcTest::isolate());
Isolate* isolate = CcTest::i_isolate();
LocalContext context;
int size_upper_limit = 0;
int count_upper_limit = 0;
HeapIterator it(CcTest::heap());
for (HeapObject* obj = it.next(); obj != NULL; obj = it.next()) {
size_upper_limit += obj->Size();
count_upper_limit++;
}
ContextMeasure measure(*isolate->native_context());
PrintF("Context size : %d bytes\n", measure.Size());
PrintF("Context object count: %d\n", measure.Count());
CHECK_LE(1000, measure.Count());
CHECK_LE(50000, measure.Size());
CHECK_LE(measure.Count(), count_upper_limit);
CHECK_LE(measure.Size(), size_upper_limit);
}
......@@ -614,6 +614,8 @@
'../../src/compiler/zone-pool.h',
'../../src/compiler.cc',
'../../src/compiler.h',
'../../src/context-measure.cc',
'../../src/context-measure.h',
'../../src/contexts.cc',
'../../src/contexts.h',
'../../src/conversions-inl.h',
......
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