blob: 46965376694d6e082f643353603da735d1f7394d [file] [log] [blame]
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "vm/class_table.h"
#include "vm/flags.h"
#include "vm/freelist.h"
#include "vm/heap.h"
#include "vm/object.h"
#include "vm/raw_object.h"
#include "vm/visitor.h"
namespace dart {
DEFINE_FLAG(bool, print_class_table, false, "Print initial class table.");
ClassTable::ClassTable()
: top_(kNumPredefinedCids), capacity_(0), table_(NULL),
class_heap_stats_table_(NULL),
predefined_class_heap_stats_table_(NULL) {
if (Dart::vm_isolate() == NULL) {
capacity_ = initial_capacity_;
table_ = reinterpret_cast<RawClass**>(
calloc(capacity_, sizeof(RawClass*))); // NOLINT
} else {
// Duplicate the class table from the VM isolate.
ClassTable* vm_class_table = Dart::vm_isolate()->class_table();
capacity_ = vm_class_table->capacity_;
table_ = reinterpret_cast<RawClass**>(
calloc(capacity_, sizeof(RawClass*))); // NOLINT
for (intptr_t i = kObjectCid; i < kInstanceCid; i++) {
table_[i] = vm_class_table->At(i);
}
table_[kFreeListElement] = vm_class_table->At(kFreeListElement);
table_[kDynamicCid] = vm_class_table->At(kDynamicCid);
table_[kVoidCid] = vm_class_table->At(kVoidCid);
class_heap_stats_table_ = reinterpret_cast<ClassHeapStats*>(
calloc(capacity_, sizeof(ClassHeapStats))); // NOLINT
for (intptr_t i = 0; i < capacity_; i++) {
class_heap_stats_table_[i].Initialize();
}
}
predefined_class_heap_stats_table_ = reinterpret_cast<ClassHeapStats*>(
calloc(kNumPredefinedCids, sizeof(ClassHeapStats))); // NOLINT
for (intptr_t i = 0; i < kNumPredefinedCids; i++) {
predefined_class_heap_stats_table_[i].Initialize();
}
}
ClassTable::~ClassTable() {
free(table_);
free(predefined_class_heap_stats_table_);
free(class_heap_stats_table_);
}
void ClassTable::Register(const Class& cls) {
intptr_t index = cls.id();
if (index != kIllegalCid) {
ASSERT(index > 0);
ASSERT(index < kNumPredefinedCids);
ASSERT(table_[index] == 0);
ASSERT(index < capacity_);
table_[index] = cls.raw();
// Add the vtable for this predefined class into the static vtable registry
// if it has not been setup yet.
cpp_vtable cls_vtable = cls.handle_vtable();
cpp_vtable table_entry = Object::builtin_vtables_[index];
ASSERT((table_entry == 0) || (table_entry == cls_vtable));
if (table_entry == 0) {
Object::builtin_vtables_[index] = cls_vtable;
}
} else {
if (top_ == capacity_) {
// Grow the capacity of the class table.
intptr_t new_capacity = capacity_ + capacity_increment_;
RawClass** new_table = reinterpret_cast<RawClass**>(
realloc(table_, new_capacity * sizeof(RawClass*))); // NOLINT
ClassHeapStats* new_stats_table = reinterpret_cast<ClassHeapStats*>(
realloc(class_heap_stats_table_,
new_capacity * sizeof(ClassHeapStats))); // NOLINT
for (intptr_t i = capacity_; i < new_capacity; i++) {
new_table[i] = NULL;
new_stats_table[i].Initialize();
}
capacity_ = new_capacity;
table_ = new_table;
class_heap_stats_table_ = new_stats_table;
}
ASSERT(top_ < capacity_);
cls.set_id(top_);
table_[top_] = cls.raw();
top_++; // Increment next index.
}
}
void ClassTable::VisitObjectPointers(ObjectPointerVisitor* visitor) {
ASSERT(visitor != NULL);
visitor->VisitPointers(reinterpret_cast<RawObject**>(&table_[0]), top_);
}
void ClassTable::Print() {
Class& cls = Class::Handle();
String& name = String::Handle();
for (intptr_t i = 1; i < top_; i++) {
cls = At(i);
if (cls.raw() != reinterpret_cast<RawClass*>(0)) {
name = cls.Name();
OS::Print("%" Pd ": %s\n", i, name.ToCString());
}
}
}
void ClassTable::PrintToJSONStream(JSONStream* stream) {
Class& cls = Class::Handle();
JSONObject jsobj(stream);
jsobj.AddProperty("type", "ClassList");
{
JSONArray members(&jsobj, "members");
for (intptr_t i = 1; i < top_; i++) {
if (HasValidClassAt(i)) {
cls = At(i);
members.AddValue(cls);
}
}
}
}
void ClassHeapStats::Initialize() {
allocated_before_gc_old_space = 0;
allocated_before_gc_new_space = 0;
allocated_size_before_gc_old_space = 0;
allocated_size_before_gc_new_space = 0;
live_after_gc_old_space = 0;
live_after_gc_new_space = 0;
live_size_after_gc_old_space = 0;
live_size_after_gc_new_space = 0;
allocated_since_gc_new_space = 0;
allocated_since_gc_old_space = 0;
allocated_size_since_gc_new_space = 0;
allocated_size_since_gc_old_space = 0;
}
void ClassHeapStats::ResetAtNewGC() {
allocated_before_gc_new_space = live_after_gc_new_space +
allocated_since_gc_new_space;
allocated_size_before_gc_new_space = live_size_after_gc_new_space +
allocated_size_since_gc_new_space;
live_after_gc_new_space = 0;
live_size_after_gc_new_space = 0;
allocated_since_gc_new_space = 0;
allocated_size_since_gc_new_space = 0;
}
void ClassHeapStats::ResetAtOldGC() {
allocated_before_gc_old_space = live_after_gc_old_space +
allocated_since_gc_old_space;
allocated_size_before_gc_old_space = live_size_after_gc_old_space +
allocated_size_since_gc_old_space;
live_after_gc_old_space = 0;
live_size_after_gc_old_space = 0;
allocated_since_gc_old_space = 0;
allocated_size_since_gc_old_space = 0;
}
void ClassHeapStats::UpdateSize(intptr_t instance_size) {
ASSERT(instance_size > 0);
// For classes with fixed instance size we do not emit code to update
// the size statistics. Update them here.
allocated_size_before_gc_old_space =
allocated_before_gc_old_space * instance_size;
allocated_size_before_gc_new_space =
allocated_before_gc_new_space * instance_size;
live_size_after_gc_old_space =
live_after_gc_old_space * instance_size;
live_size_after_gc_new_space =
live_after_gc_new_space * instance_size;
allocated_size_since_gc_new_space =
allocated_since_gc_new_space * instance_size;
allocated_size_since_gc_old_space =
allocated_since_gc_old_space * instance_size;
}
void ClassHeapStats::PrintTOJSONArray(const Class& cls, JSONArray* array) {
JSONObject obj(array);
obj.AddProperty("type", "ClassHeapStats");
obj.AddProperty("class", cls);
{
JSONArray new_stats(&obj, "new");
new_stats.AddValue(allocated_before_gc_new_space);
new_stats.AddValue(allocated_size_before_gc_new_space);
new_stats.AddValue(live_after_gc_new_space);
new_stats.AddValue(live_size_after_gc_new_space);
new_stats.AddValue(allocated_since_gc_new_space);
new_stats.AddValue(allocated_size_since_gc_new_space);
}
{
JSONArray old_stats(&obj, "old");
old_stats.AddValue(allocated_before_gc_old_space);
old_stats.AddValue(allocated_size_before_gc_old_space);
old_stats.AddValue(live_after_gc_old_space);
old_stats.AddValue(live_size_after_gc_old_space);
old_stats.AddValue(allocated_since_gc_old_space);
old_stats.AddValue(allocated_size_since_gc_old_space);
}
}
void ClassTable::UpdateAllocatedNew(intptr_t cid, intptr_t size) {
ClassHeapStats* stats = StatsAt(cid);
ASSERT(stats != NULL);
ASSERT(size != 0);
stats->allocated_since_gc_new_space++;
stats->allocated_size_since_gc_new_space += size;
}
void ClassTable::UpdateAllocatedOld(intptr_t cid, intptr_t size) {
ClassHeapStats* stats = StatsAt(cid);
ASSERT(stats != NULL);
ASSERT(size != 0);
stats->allocated_since_gc_old_space++;
stats->allocated_size_since_gc_old_space += size;
}
bool ClassTable::ShouldUpdateSizeForClassId(intptr_t cid) {
return !RawObject::IsVariableSizeClassId(cid);
}
ClassHeapStats* ClassTable::StatsAt(intptr_t cid) {
ASSERT(cid > 0);
if (cid < kNumPredefinedCids) {
return &predefined_class_heap_stats_table_[cid];
}
ASSERT(cid < top_);
return &class_heap_stats_table_[cid];
}
void ClassTable::ResetCountersOld() {
for (intptr_t i = 0; i < kNumPredefinedCids; i++) {
predefined_class_heap_stats_table_[i].ResetAtOldGC();
}
for (intptr_t i = kNumPredefinedCids; i < top_; i++) {
class_heap_stats_table_[i].ResetAtOldGC();
}
}
void ClassTable::ResetCountersNew() {
for (intptr_t i = 0; i < kNumPredefinedCids; i++) {
predefined_class_heap_stats_table_[i].ResetAtNewGC();
}
for (intptr_t i = kNumPredefinedCids; i < top_; i++) {
class_heap_stats_table_[i].ResetAtNewGC();
}
}
void ClassTable::AllocationProfilePrintToJSONStream(JSONStream* stream) {
Isolate* isolate = Isolate::Current();
ASSERT(isolate != NULL);
Heap* heap = isolate->heap();
ASSERT(heap != NULL);
JSONObject obj(stream);
obj.AddProperty("type", "AllocationProfile");
{
JSONObject heaps(&obj, "heaps");
{
heap->PrintToJSONObject(Heap::kNew, &heaps);
}
{
heap->PrintToJSONObject(Heap::kOld, &heaps);
}
}
{
Class& cls = Class::Handle();
JSONArray arr(&obj, "members");
for (intptr_t i = 1; i < kNumPredefinedCids; i++) {
if (!HasValidClassAt(i) || (i == kFreeListElement) || (i == kSmiCid)) {
continue;
}
cls = At(i);
if (!(cls.is_finalized() || cls.is_prefinalized())) {
// Not finalized.
continue;
}
if (ShouldUpdateSizeForClassId(i)) {
intptr_t instance_size = cls.instance_size();
predefined_class_heap_stats_table_[i].UpdateSize(instance_size);
}
predefined_class_heap_stats_table_[i].PrintTOJSONArray(cls, &arr);
}
for (intptr_t i = kNumPredefinedCids; i < top_; i++) {
if (!HasValidClassAt(i)) {
continue;
}
cls = At(i);
if (!(cls.is_finalized() || cls.is_prefinalized())) {
// Not finalized.
continue;
}
if (ShouldUpdateSizeForClassId(i)) {
intptr_t instance_size = cls.instance_size();
class_heap_stats_table_[i].UpdateSize(instance_size);
}
class_heap_stats_table_[i].PrintTOJSONArray(cls, &arr);
}
}
}
void ClassTable::UpdateLiveOld(intptr_t cid, intptr_t size) {
ClassHeapStats* stats = StatsAt(cid);
ASSERT(stats != NULL);
ASSERT(size >= 0);
stats->live_after_gc_old_space++;
stats->live_size_after_gc_old_space += size;
}
void ClassTable::UpdateLiveNew(intptr_t cid, intptr_t size) {
ClassHeapStats* stats = StatsAt(cid);
ASSERT(stats != NULL);
ASSERT(size >= 0);
stats->live_after_gc_new_space++;
stats->live_size_after_gc_new_space += size;
}
} // namespace dart