Flutter Engine
The Flutter Engine
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
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 {
327 heap->PrintToJSONObject(Heap::kNew, &heaps);
328 }
329 {
330 heap->PrintToJSONObject(Heap::kOld, &heaps);
331 }
332 }
333
334 {
335 JSONObject memory(&obj, "memoryUsage");
336 {
337 heap->PrintMemoryUsageJSON(&memory);
338 }
339 }
340
341 Thread* thread = Thread::Current();
342 CountObjectsVisitor visitor(thread, NumCids());
343 {
344 HeapIterationScope iter(thread);
345 iter.IterateObjects(&visitor);
346 isolate->group()->VisitWeakPersistentHandles(&visitor);
347 }
348
349 {
350 JSONArray arr(&obj, "members");
351 Class& cls = Class::Handle();
352 for (intptr_t i = 3; i < classes_.num_cids(); i++) {
353 if (!HasValidClassAt(i)) continue;
354
355 cls = At(i);
356 if (cls.IsNull()) continue;
357
358 JSONObject obj(&arr);
359 obj.AddProperty("type", "ClassHeapStats");
360 obj.AddProperty("class", cls);
361 intptr_t count = visitor.new_count_[i] + visitor.old_count_[i];
362 intptr_t size = visitor.new_size_[i] + visitor.old_size_[i];
363 obj.AddProperty64("instancesAccumulated", count);
364 obj.AddProperty64("accumulatedSize", size);
365 obj.AddProperty64("instancesCurrent", count);
366 obj.AddProperty64("bytesCurrent", size);
367
368 if (internal) {
369 {
370 JSONArray new_stats(&obj, "_new");
371 new_stats.AddValue(visitor.new_count_[i]);
372 new_stats.AddValue(visitor.new_size_[i]);
373 new_stats.AddValue(visitor.new_external_size_[i]);
374 }
375 {
376 JSONArray old_stats(&obj, "_old");
377 old_stats.AddValue(visitor.old_count_[i]);
378 old_stats.AddValue(visitor.old_size_[i]);
379 old_stats.AddValue(visitor.old_external_size_[i]);
380 }
381 }
382 }
383 }
384}
385#endif // !PRODUCT
386
388 : pending_freed_(new MallocGrowableArray<std::pair<void*, Deleter>>()) {}
389
391 FreePending();
392 delete pending_freed_;
393}
394
396 if (ptr != nullptr) {
397 pending_freed_->Add(std::make_pair(
398 ptr, [](void* ptr) { delete static_cast<ClassTable*>(ptr); }));
399 }
400}
401
403 if (ptr != nullptr) {
404 pending_freed_->Add(std::make_pair(ptr, nullptr));
405 }
406}
407
409 while (!pending_freed_->is_empty()) {
410 auto [ptr, deleter] = pending_freed_->RemoveLast();
411 if (deleter == nullptr) {
412 free(ptr);
413 } else {
414 deleter(ptr);
415 }
416 }
417}
418
419} // namespace dart
int count
Definition: FontMgrTest.cpp:50
SI F table(const skcms_Curve *curve, F v)
ObjectPtr At(intptr_t index) const
Definition: object.h:10875
intptr_t Length() const
Definition: object.h:10829
void Add(const T &value)
intptr_t num_cids() const
Definition: class_table.h:249
T & At(intptr_t index)
Definition: class_table.h:236
intptr_t AddRow(bool *did_grow)
Definition: class_table.h:181
void AllocateIndex(intptr_t index, bool *did_grow)
Definition: class_table.h:176
void Free(ClassTable *table)
Definition: class_table.cc:395
void Register(const Class &cls)
Definition: class_table.cc:65
void CopySizesFromClassObjects()
Definition: class_table.cc:146
ClassPtr At(intptr_t cid) const
Definition: class_table.h:362
void SetAt(intptr_t index, ClassPtr raw_cls)
Definition: class_table.cc:153
static intptr_t CidFromTopLevelIndex(intptr_t index)
Definition: class_table.h:503
void UpdateCachedAllocationTracingStateTablePointer()
Definition: class_table.h:423
void AllocationProfilePrintJSON(JSONStream *stream, bool internal)
Definition: class_table.cc:305
void UnregisterTopLevel(intptr_t index)
Definition: class_table.cc:116
int32_t SizeAt(intptr_t index) const
Definition: class_table.h:369
void VisitObjectPointers(ObjectPointerVisitor *visitor)
Definition: class_table.cc:127
intptr_t NumCids() const
Definition: class_table.h:447
void UpdateClassSize(intptr_t cid, ClassPtr raw_cls)
Definition: class_table.cc:164
void Remap(intptr_t *old_to_new_cids)
Definition: class_table.cc:122
void RegisterTopLevel(const Class &cls)
Definition: class_table.cc:92
bool HasValidClassAt(intptr_t cid) const
Definition: class_table.h:386
void PopulateUserVisibleNames()
Definition: class_table.cc:278
void AllocateIndex(intptr_t index)
Definition: class_table.cc:102
ClassTable(ClassTableAllocator *allocator)
Definition: class_table.cc:22
static intptr_t IndexFromTopLevelCid(intptr_t cid)
Definition: class_table.h:498
static bool IsTopLevelCid(intptr_t cid)
Definition: class_table.h:496
void PrintToJSONObject(JSONObject *object)
Definition: class_table.cc:291
const char * UserVisibleNameFor(intptr_t cid)
Definition: class_table.h:434
intptr_t id() const
Definition: object.h:1233
intptr_t target_instance_size() const
Definition: object.h:1147
void SetUserVisibleNameInClassTable()
Definition: object.cc:5383
ArrayPtr fields() const
Definition: object.h:1615
intptr_t host_instance_size() const
Definition: object.h:1143
bool is_abstract() const
Definition: object.h:1696
StringPtr Name() const
Definition: object.cc:2977
void set_id(intptr_t value) const
Definition: object.h:1234
bool IsTopLevel() const
Definition: object.cc:6121
const char * UserVisibleNameCString() const
Definition: object.cc:2998
bool is_finalized() const
Definition: object.h:1723
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:12082
intptr_t TargetOffset() const
Definition: object.h:13246
bool is_static() const
Definition: object.h:4440
void IterateObjects(ObjectVisitor *visitor) const
Definition: heap.cc:335
@ kNew
Definition: heap.h:38
@ kOld
Definition: heap.h:39
void PrintMemoryUsageJSON(JSONStream *stream) const
Definition: heap.cc:992
void PrintToJSONObject(Space space, JSONObject *object) const
Definition: heap.cc:984
void set_cached_class_table_table(ClassPtr *cached_class_table_table)
Definition: isolate.h:393
static IsolateGroup * Current()
Definition: isolate.h:539
ClassTable * class_table() const
Definition: isolate.h:496
void VisitWeakPersistentHandles(HandleVisitor *visitor)
Definition: isolate.cc:2998
static Isolate * Current()
Definition: isolate.h:986
IsolateGroup * group() const
Definition: isolate.h:1037
void AddValue(bool b) const
Definition: json_stream.h:494
void AddProperty64(const char *name, int64_t i) const
Definition: json_stream.h:401
void AddProperty(const char *name, bool b) const
Definition: json_stream.h:395
void AddPropertyF(const char *name, const char *format,...) const PRINTF_ATTRIBUTE(3
Definition: json_stream.cc:589
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:362
#define ASSERT(E)
Definition: dart_vm.cc:33
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
DEFINE_FLAG(bool, print_cluster_information, false, "Print information about clusters written to snapshot")
const intptr_t cid
COMPILE_ASSERT(kUnreachableReference==WeakTable::kNoValue)
constexpr intptr_t kLastInternalOnlyCid
Definition: class_id.h:289
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
Definition: ref_ptr.h:256
#define Pd64
Definition: globals.h:416
#define Pd
Definition: globals.h:408