Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
class_table.cc
Go to the documentation of this file.
1// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#include "vm/class_table.h"
6
7#include <memory>
8
9#include "platform/atomic.h"
10#include "vm/flags.h"
11#include "vm/growable_array.h"
12#include "vm/heap/heap.h"
13#include "vm/object.h"
14#include "vm/object_graph.h"
15#include "vm/raw_object.h"
16#include "vm/visitor.h"
17
18namespace dart {
19
20DEFINE_FLAG(bool, print_class_table, false, "Print initial class table.");
21
23 : allocator_(allocator),
24 classes_(allocator),
25 top_level_classes_(allocator) {
26 if (Dart::vm_isolate() == nullptr) {
27 classes_.SetNumCidsAndCapacity(kNumPredefinedCids, kInitialCapacity);
28 } else {
29 // Duplicate the class table from the VM isolate.
30 ClassTable* vm_class_table = Dart::vm_isolate_group()->class_table();
31 classes_.SetNumCidsAndCapacity(kNumPredefinedCids,
32 vm_class_table->classes_.capacity());
33
34 const auto copy_info_for_cid = [&](intptr_t cid) {
35 classes_.At<kClassIndex>(cid) = vm_class_table->At(cid);
36 classes_.At<kSizeIndex>(cid) = vm_class_table->SizeAt(cid);
37 };
38
39 // The following cids don't have a corresponding class object in Dart code.
40 // We therefore need to initialize them eagerly.
41 COMPILE_ASSERT(kFirstInternalOnlyCid == kObjectCid + 1);
42 for (intptr_t i = kObjectCid; i <= kLastInternalOnlyCid; i++) {
43 copy_info_for_cid(i);
44 }
45 copy_info_for_cid(kTypeArgumentsCid);
46 copy_info_for_cid(kFreeListElement);
47 copy_info_for_cid(kForwardingCorpse);
48 copy_info_for_cid(kDynamicCid);
49 copy_info_for_cid(kVoidCid);
50 }
52}
53
55#if !defined(PRODUCT) || defined(FORCE_INCLUDE_SAMPLING_HEAP_PROFILER)
56 for (intptr_t i = 1; i < classes_.num_cids(); i++) {
57 const char* name = UserVisibleNameFor(i);
58 if (name != nullptr) {
59 free(const_cast<char*>(name));
60 }
61 }
62#endif // !defined(PRODUCT) || defined(FORCE_INCLUDE_SAMPLING_HEAP_PROFILER)
63}
64
65void ClassTable::Register(const Class& cls) {
66 ASSERT(Thread::Current()->IsDartMutatorThread());
67 ASSERT(cls.id() == kIllegalCid || cls.id() < kNumPredefinedCids);
68 bool did_grow = false;
69 const classid_t cid =
70 cls.id() != kIllegalCid ? cls.id() : classes_.AddRow(&did_grow);
72
73 const intptr_t instance_size =
74 cls.is_abstract() ? 0 : Class::host_instance_size(cls.ptr());
75
76 cls.set_id(cid);
77 classes_.At<kClassIndex>(cid) = cls.ptr();
78 classes_.At<kSizeIndex>(cid) = static_cast<int32_t>(instance_size);
79#if !defined(PRODUCT) || defined(FORCE_INCLUDE_SAMPLING_HEAP_PROFILER)
80 classes_.At<kClassNameIndex>(cid) = nullptr;
81#endif // !defined(PRODUCT) || defined(FORCE_INCLUDE_SAMPLING_HEAP_PROFILER)
82
83 if (did_grow) {
85 classes_.GetColumn<kClassIndex>());
87 } else {
88 std::atomic_thread_fence(std::memory_order_release);
89 }
90}
91
93 ASSERT(Thread::Current()->IsDartMutatorThread());
94 ASSERT(cls.id() == kIllegalCid);
95
96 bool did_grow = false;
97 const intptr_t index = top_level_classes_.AddRow(&did_grow);
99 top_level_classes_.At<kClassIndex>(index) = cls.ptr();
100}
101
102void ClassTable::AllocateIndex(intptr_t index) {
103 bool did_grow = false;
104 if (IsTopLevelCid(index)) {
105 top_level_classes_.AllocateIndex(IndexFromTopLevelCid(index), &did_grow);
106 return;
107 }
108
109 classes_.AllocateIndex(index, &did_grow);
110 if (did_grow) {
113 }
114}
115
118 const intptr_t tlc_index = IndexFromTopLevelCid(cid);
119 top_level_classes_.At<kClassIndex>(tlc_index) = nullptr;
120}
121
122void ClassTable::Remap(intptr_t* old_to_new_cid) {
123 ASSERT(Thread::Current()->OwnsSafepoint());
124 classes_.Remap(old_to_new_cid);
125}
126
128 ASSERT(visitor != nullptr);
129 visitor->set_gc_root_type("class table");
130
131 const auto visit = [&](ClassPtr* table, intptr_t num_cids) {
132 if (num_cids == 0) {
133 return;
134 }
135 ObjectPtr* from = reinterpret_cast<ObjectPtr*>(&table[0]);
136 ObjectPtr* to = reinterpret_cast<ObjectPtr*>(&table[num_cids - 1]);
137 visitor->VisitPointers(from, to);
138 };
139
140 visit(classes_.GetColumn<kClassIndex>(), classes_.num_cids());
141 visit(top_level_classes_.GetColumn<kClassIndex>(),
142 top_level_classes_.num_cids());
143 visitor->clear_gc_root_type();
144}
145
147 ASSERT(kIllegalCid == 0);
148 for (intptr_t i = 1; i < classes_.num_cids(); i++) {
149 UpdateClassSize(i, classes_.At<kClassIndex>(i));
150 }
151}
152
153void ClassTable::SetAt(intptr_t cid, ClassPtr raw_cls) {
154 if (IsTopLevelCid(cid)) {
155 top_level_classes_.At<kClassIndex>(IndexFromTopLevelCid(cid)) = raw_cls;
156 return;
157 }
158
159 // This is called by snapshot reader and class finalizer.
160 UpdateClassSize(cid, raw_cls);
161 classes_.At<kClassIndex>(cid) = raw_cls;
162}
163
164void ClassTable::UpdateClassSize(intptr_t cid, ClassPtr raw_cls) {
165 ASSERT(IsolateGroup::Current()->program_lock()->IsCurrentThreadWriter());
166 ASSERT(!IsTopLevelCid(cid)); // "top-level" classes don't get instantiated
167 const intptr_t size =
168 raw_cls == nullptr ? 0 : Class::host_instance_size(raw_cls);
169 classes_.At<kSizeIndex>(cid) = static_cast<int32_t>(size);
170}
171
173 Class& cls = Class::Handle();
174 for (intptr_t cid = kNumPredefinedCids; cid < classes_.num_cids(); cid++) {
175 // Some of the class table entries maybe nullptr as we create some
176 // top level classes but do not add them to the list of anonymous
177 // classes in a library if there are no top level fields or functions.
178 // Since there are no references to these top level classes they are
179 // not written into a full snapshot and will not be recreated when
180 // we read back the full snapshot. These class slots end up with nullptr
181 // entries.
182 if (HasValidClassAt(cid)) {
183 cls = At(cid);
184 ASSERT(cls.IsClass());
185#if defined(DART_PRECOMPILER)
186 // Precompiler can drop classes and set their id() to kIllegalCid.
187 // It still leaves them in the class table so dropped program
188 // structure could still be accessed while writing debug info.
189 ASSERT((cls.id() == cid) || (cls.id() == kIllegalCid));
190#else
191 ASSERT(cls.id() == cid);
192#endif // defined(DART_PRECOMPILER)
193 }
194 }
195}
196
198 Class& cls = Class::Handle();
200
201 for (intptr_t i = 1; i < classes_.num_cids(); i++) {
202 if (!HasValidClassAt(i)) {
203 continue;
204 }
205 cls = At(i);
206 if (cls.ptr() != nullptr) {
207 name = cls.Name();
208 OS::PrintErr("%" Pd ": %s\n", i, name.ToCString());
209 }
210 }
211}
212
213#if defined(DART_PRECOMPILER)
214void ClassTable::PrintObjectLayout(const char* filename) {
215 Class& cls = Class::Handle();
216 Array& fields = Array::Handle();
217 Field& field = Field::Handle();
218
219 JSONWriter js;
220 js.OpenArray();
221 for (intptr_t i = ClassId::kObjectCid; i < classes_.num_cids(); i++) {
222 if (!HasValidClassAt(i)) {
223 continue;
224 }
225 cls = At(i);
226 ASSERT(!cls.IsNull());
227 ASSERT(cls.id() != kIllegalCid);
228 ASSERT(cls.is_finalized()); // Precompiler already finalized all classes.
229 ASSERT(!cls.IsTopLevel());
230 js.OpenObject();
231 js.PrintProperty("class", cls.UserVisibleNameCString());
232 js.PrintProperty("size", cls.target_instance_size());
233 js.OpenArray("fields");
234 fields = cls.fields();
235 if (!fields.IsNull()) {
236 for (intptr_t i = 0, n = fields.Length(); i < n; ++i) {
237 field ^= fields.At(i);
238 js.OpenObject();
239 js.PrintProperty("field", field.UserVisibleNameCString());
240 if (field.is_static()) {
241 js.PrintPropertyBool("static", true);
242 } else {
243 js.PrintProperty("offset", field.TargetOffset());
244 }
245 js.CloseObject();
246 }
247 }
248 js.CloseArray();
249 js.CloseObject();
250 }
251 js.CloseArray();
252
253 auto file_open = Dart::file_open_callback();
254 auto file_write = Dart::file_write_callback();
255 auto file_close = Dart::file_close_callback();
256 if ((file_open == nullptr) || (file_write == nullptr) ||
257 (file_close == nullptr)) {
258 OS::PrintErr("warning: Could not access file callbacks.");
259 return;
260 }
261
262 void* file = file_open(filename, /*write=*/true);
263 if (file == nullptr) {
264 OS::PrintErr("warning: Failed to write object layout: %s\n", filename);
265 return;
266 }
267
268 char* output = nullptr;
269 intptr_t output_length = 0;
270 js.Steal(&output, &output_length);
271 file_write(output, output_length, file);
272 free(output);
273 file_close(file);
274}
275#endif // defined(DART_PRECOMPILER)
276
277#if !defined(PRODUCT) || defined(FORCE_INCLUDE_SAMPLING_HEAP_PROFILER)
279 Class& cls = Class::Handle();
280 for (intptr_t i = 0; i < classes_.num_cids(); ++i) {
281 if (HasValidClassAt(i) && UserVisibleNameFor(i) == nullptr) {
282 cls = At(i);
284 }
285 }
286}
287#endif // !defined(PRODUCT) || defined(FORCE_INCLUDE_SAMPLING_HEAP_PROFILER)
288
289#if !defined(PRODUCT)
290
292 Class& cls = Class::Handle();
293 object->AddProperty("type", "ClassList");
294 {
295 JSONArray members(object, "classes");
296 for (intptr_t i = ClassId::kObjectCid; i < classes_.num_cids(); i++) {
297 if (HasValidClassAt(i)) {
298 cls = At(i);
299 members.AddValue(cls);
300 }
301 }
302 }
303}
304
306 Isolate* isolate = Isolate::Current();
307 ASSERT(isolate != nullptr);
308 auto isolate_group = isolate->group();
309 Heap* heap = isolate_group->heap();
310 ASSERT(heap != nullptr);
311 JSONObject obj(stream);
312 obj.AddProperty("type", "AllocationProfile");
313 if (isolate_group->last_allocationprofile_accumulator_reset_timestamp() !=
314 0) {
315 obj.AddPropertyF(
316 "dateLastAccumulatorReset", "%" Pd64 "",
317 isolate_group->last_allocationprofile_accumulator_reset_timestamp());
318 }
319 if (isolate_group->last_allocationprofile_gc_timestamp() != 0) {
320 obj.AddPropertyF("dateLastServiceGC", "%" Pd64 "",
321 isolate_group->last_allocationprofile_gc_timestamp());
322 }
323
324 if (internal) {
325 JSONObject heaps(&obj, "_heaps");
326 { heap->PrintToJSONObject(Heap::kNew, &heaps); }
327 { heap->PrintToJSONObject(Heap::kOld, &heaps); }
328 }
329
330 {
331 JSONObject memory(&obj, "memoryUsage");
332 { heap->PrintMemoryUsageJSON(&memory); }
333 }
334
335 Thread* thread = Thread::Current();
336 CountObjectsVisitor visitor(thread, NumCids());
337 {
338 HeapIterationScope iter(thread);
339 iter.IterateObjects(&visitor);
340 isolate->group()->VisitWeakPersistentHandles(&visitor);
341 }
342
343 {
344 JSONArray arr(&obj, "members");
345 Class& cls = Class::Handle();
346 for (intptr_t i = 3; i < classes_.num_cids(); i++) {
347 if (!HasValidClassAt(i)) continue;
348
349 cls = At(i);
350 if (cls.IsNull()) continue;
351
352 JSONObject obj(&arr);
353 obj.AddProperty("type", "ClassHeapStats");
354 obj.AddProperty("class", cls);
355 intptr_t count = visitor.new_count_[i] + visitor.old_count_[i];
356 intptr_t size = visitor.new_size_[i] + visitor.old_size_[i];
357 obj.AddProperty64("instancesAccumulated", count);
358 obj.AddProperty64("accumulatedSize", size);
359 obj.AddProperty64("instancesCurrent", count);
360 obj.AddProperty64("bytesCurrent", size);
361
362 if (internal) {
363 {
364 JSONArray new_stats(&obj, "_new");
365 new_stats.AddValue(visitor.new_count_[i]);
366 new_stats.AddValue(visitor.new_size_[i]);
367 new_stats.AddValue(visitor.new_external_size_[i]);
368 }
369 {
370 JSONArray old_stats(&obj, "_old");
371 old_stats.AddValue(visitor.old_count_[i]);
372 old_stats.AddValue(visitor.old_size_[i]);
373 old_stats.AddValue(visitor.old_external_size_[i]);
374 }
375 }
376 }
377 }
378}
379#endif // !PRODUCT
380
382 : pending_freed_(new MallocGrowableArray<std::pair<void*, Deleter>>()) {}
383
385 FreePending();
386 delete pending_freed_;
387}
388
390 if (ptr != nullptr) {
391 pending_freed_->Add(std::make_pair(
392 ptr, [](void* ptr) { delete static_cast<ClassTable*>(ptr); }));
393 }
394}
395
397 if (ptr != nullptr) {
398 pending_freed_->Add(std::make_pair(ptr, nullptr));
399 }
400}
401
403 while (!pending_freed_->is_empty()) {
404 auto [ptr, deleter] = pending_freed_->RemoveLast();
405 if (deleter == nullptr) {
406 free(ptr);
407 } else {
408 deleter(ptr);
409 }
410 }
411}
412
413} // namespace dart
int count
#define COMPILE_ASSERT(expr)
Definition assert.h:339
ObjectPtr At(intptr_t index) const
Definition object.h:10854
intptr_t Length() const
Definition object.h:10808
void Add(const T &value)
intptr_t num_cids() const
T & At(intptr_t index)
intptr_t AddRow(bool *did_grow)
void AllocateIndex(intptr_t index, bool *did_grow)
void Free(ClassTable *table)
void Register(const Class &cls)
void CopySizesFromClassObjects()
ClassPtr At(intptr_t cid) const
void SetAt(intptr_t index, ClassPtr raw_cls)
static intptr_t CidFromTopLevelIndex(intptr_t index)
void UpdateCachedAllocationTracingStateTablePointer()
void AllocationProfilePrintJSON(JSONStream *stream, bool internal)
void UnregisterTopLevel(intptr_t index)
int32_t SizeAt(intptr_t index) const
void VisitObjectPointers(ObjectPointerVisitor *visitor)
intptr_t NumCids() const
void UpdateClassSize(intptr_t cid, ClassPtr raw_cls)
void Remap(intptr_t *old_to_new_cids)
void RegisterTopLevel(const Class &cls)
bool HasValidClassAt(intptr_t cid) const
void PopulateUserVisibleNames()
void AllocateIndex(intptr_t index)
ClassTable(ClassTableAllocator *allocator)
static intptr_t IndexFromTopLevelCid(intptr_t cid)
static bool IsTopLevelCid(intptr_t cid)
void PrintToJSONObject(JSONObject *object)
const char * UserVisibleNameFor(intptr_t cid)
intptr_t id() const
Definition object.h:1235
intptr_t target_instance_size() const
Definition object.h:1149
void SetUserVisibleNameInClassTable()
Definition object.cc:5438
ArrayPtr fields() const
Definition object.h:1617
intptr_t host_instance_size() const
Definition object.h:1145
bool is_abstract() const
Definition object.h:1698
StringPtr Name() const
Definition object.cc:3038
void set_id(intptr_t value) const
Definition object.h:1236
bool IsTopLevel() const
Definition object.cc:6176
const char * UserVisibleNameCString() const
Definition object.cc:3059
bool is_finalized() const
Definition object.h:1725
static Dart_FileWriteCallback file_write_callback()
Definition dart.h:125
static IsolateGroup * vm_isolate_group()
Definition dart.h:69
static Dart_FileOpenCallback file_open_callback()
Definition dart.h:119
static Isolate * vm_isolate()
Definition dart.h:68
static Dart_FileCloseCallback file_close_callback()
Definition dart.h:128
const char * UserVisibleNameCString() const
Definition object.cc:12133
intptr_t TargetOffset() const
Definition object.h:13220
bool is_static() const
Definition object.h:4418
void IterateObjects(ObjectVisitor *visitor) const
Definition heap.cc:334
@ kNew
Definition heap.h:38
@ kOld
Definition heap.h:39
void PrintMemoryUsageJSON(JSONStream *stream) const
Definition heap.cc:981
void PrintToJSONObject(Space space, JSONObject *object) const
Definition heap.cc:973
void set_cached_class_table_table(ClassPtr *cached_class_table_table)
Definition isolate.h:392
static IsolateGroup * Current()
Definition isolate.h:534
ClassTable * class_table() const
Definition isolate.h:491
void VisitWeakPersistentHandles(HandleVisitor *visitor)
Definition isolate.cc:2952
static Isolate * Current()
Definition isolate.h:939
IsolateGroup * group() const
Definition isolate.h:990
void AddValue(bool b) const
void AddProperty64(const char *name, int64_t i) const
void AddProperty(const char *name, bool b) const
void AddPropertyF(const char *name, const char *format,...) const PRINTF_ATTRIBUTE(3
static void static void PrintErr(const char *format,...) PRINTF_ATTRIBUTE(1
void set_gc_root_type(const char *gc_root_type)
Definition visitor.h:58
virtual void VisitPointers(ObjectPtr *first, ObjectPtr *last)=0
ObjectPtr ptr() const
Definition object.h:332
bool IsNull() const
Definition object.h:363
static Object & Handle()
Definition object.h:407
static Thread * Current()
Definition thread.h:361
#define ASSERT(E)
#define DEFINE_FLAG(type, name, default_value, comment)
Definition flags.h:16
const char *const name
int32_t classid_t
Definition globals.h:524
@ kForwardingCorpse
Definition class_id.h:225
@ kIllegalCid
Definition class_id.h:214
@ kNumPredefinedCids
Definition class_id.h:257
@ kVoidCid
Definition class_id.h:254
@ kDynamicCid
Definition class_id.h:253
@ kFreeListElement
Definition class_id.h:224
constexpr intptr_t kFirstInternalOnlyCid
Definition class_id.h:288
const intptr_t cid
constexpr intptr_t kLastInternalOnlyCid
Definition class_id.h:289
Definition ref_ptr.h:256
#define Pd64
Definition globals.h:416
#define Pd
Definition globals.h:408