Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
raw_object.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/raw_object.h"
6
7#include "vm/class_table.h"
8#include "vm/dart.h"
9#include "vm/heap/become.h"
10#include "vm/heap/freelist.h"
11#include "vm/isolate.h"
12#include "vm/isolate_reload.h"
13#include "vm/object.h"
14#include "vm/runtime_entry.h"
15#include "vm/stack_frame.h"
16#include "vm/visitor.h"
17
18namespace dart {
19
21 // All "vm-isolate" objects are pre-marked and in old space
22 // (see [Object::FinalizeVMIsolate]).
23 if (!IsOldObject() || !IsMarked()) return false;
24
25 auto heap = Dart::vm_isolate_group()->heap();
26 ASSERT(heap->UsedInWords(Heap::kNew) == 0);
27 return heap->old_space()->ContainsUnsafe(ToAddr(this));
28}
29
30void ObjectPtr::Validate(IsolateGroup* isolate_group) const {
31 // All Smi values are valid.
32 if (!IsHeapObject()) {
33 return;
34 }
35 // Slightly more readable than a segfault.
37 FATAL("RAW_NULL encountered");
38 }
39 untag()->Validate(isolate_group);
40}
41
42void UntaggedObject::Validate(IsolateGroup* isolate_group) const {
43 if (static_cast<uword>(Object::void_class_) == kHeapObjectTag) {
44 // Validation relies on properly initialized class classes. Skip if the
45 // VM is still being initialized.
46 return;
47 }
48 // Validate that the tags_ field is sensible.
49 uword tags = tags_;
50 if (IsNewObject()) {
51 if (!NewBit::decode(tags)) {
52 FATAL("New object missing kNewBit: %" Px "\n", tags);
53 }
55 FATAL("New object has kOldAndNotRememberedBit: %" Px "\n", tags);
56 }
57 } else {
58 if (NewBit::decode(tags)) {
59 FATAL("Old object has kNewBit: %" Px "\n", tags);
60 }
61 }
62 const intptr_t class_id = ClassIdTag::decode(tags);
63 if (!isolate_group->class_table()->IsValidIndex(class_id)) {
64 FATAL("Invalid class id encountered %" Pd "\n", class_id);
65 }
66 if (class_id == kNullCid &&
67 isolate_group->class_table()->HasValidClassAt(class_id)) {
68 // Null class not yet initialized; skip.
69 return;
70 }
71 intptr_t size_from_tags = SizeTag::decode(tags);
72 intptr_t size_from_class = HeapSizeFromClass(tags);
73 if ((size_from_tags != 0) && (size_from_tags != size_from_class)) {
74 FATAL(
75 "Inconsistent size encountered "
76 "cid: %" Pd ", size_from_tags: %" Pd ", size_from_class: %" Pd "\n",
77 class_id, size_from_tags, size_from_class);
78 }
79}
80
81// Can't look at the class object because it can be called during
82// compaction when the class objects are moving. Can use the class
83// id in the header and the sizes in the Class Table.
84// Cannot deference ptr()->tags_. May dereference other parts of the object.
85intptr_t UntaggedObject::HeapSizeFromClass(uword tags) const {
86 intptr_t class_id = ClassIdTag::decode(tags);
87 intptr_t instance_size = 0;
88 switch (class_id) {
89 case kCodeCid: {
90 const CodePtr raw_code = static_cast<const CodePtr>(this);
91 intptr_t pointer_offsets_length =
92 Code::PtrOffBits::decode(raw_code->untag()->state_bits_);
93 instance_size = Code::InstanceSize(pointer_offsets_length);
94 break;
95 }
96 case kInstructionsCid: {
97 const InstructionsPtr raw_instructions =
98 static_cast<const InstructionsPtr>(this);
99 intptr_t instructions_size = Instructions::Size(raw_instructions);
100 instance_size = Instructions::InstanceSize(instructions_size);
101 break;
102 }
103 case kInstructionsSectionCid: {
104 const InstructionsSectionPtr raw_section =
105 static_cast<const InstructionsSectionPtr>(this);
106 intptr_t section_size = InstructionsSection::Size(raw_section);
107 instance_size = InstructionsSection::InstanceSize(section_size);
108 break;
109 }
110 case kContextCid: {
111 const ContextPtr raw_context = static_cast<const ContextPtr>(this);
112 intptr_t num_variables = raw_context->untag()->num_variables_;
113 instance_size = Context::InstanceSize(num_variables);
114 break;
115 }
116 case kContextScopeCid: {
117 const ContextScopePtr raw_context_scope =
118 static_cast<const ContextScopePtr>(this);
119 intptr_t num_variables = raw_context_scope->untag()->num_variables_;
120 instance_size = ContextScope::InstanceSize(num_variables);
121 break;
122 }
123 case kOneByteStringCid: {
124 const OneByteStringPtr raw_string =
125 static_cast<const OneByteStringPtr>(this);
126 intptr_t string_length = Smi::Value(raw_string->untag()->length());
127 instance_size = OneByteString::InstanceSize(string_length);
128 break;
129 }
130 case kTwoByteStringCid: {
131 const TwoByteStringPtr raw_string =
132 static_cast<const TwoByteStringPtr>(this);
133 intptr_t string_length = Smi::Value(raw_string->untag()->length());
134 instance_size = TwoByteString::InstanceSize(string_length);
135 break;
136 }
137 case kArrayCid:
138 case kImmutableArrayCid: {
139 const ArrayPtr raw_array = static_cast<const ArrayPtr>(this);
140 intptr_t array_length =
141 Smi::Value(raw_array->untag()->length<std::memory_order_acquire>());
142 instance_size = Array::InstanceSize(array_length);
143 break;
144 }
145 case kWeakArrayCid: {
146 const WeakArrayPtr raw_array = static_cast<const WeakArrayPtr>(this);
147 intptr_t array_length = Smi::Value(raw_array->untag()->length());
148 instance_size = WeakArray::InstanceSize(array_length);
149 break;
150 }
151 case kObjectPoolCid: {
152 const ObjectPoolPtr raw_object_pool =
153 static_cast<const ObjectPoolPtr>(this);
154 intptr_t len = raw_object_pool->untag()->length_;
155 instance_size = ObjectPool::InstanceSize(len);
156 break;
157 }
158 case kRecordCid: {
159 const RecordPtr raw_record = static_cast<const RecordPtr>(this);
160 intptr_t num_fields =
161 RecordShape(raw_record->untag()->shape()).num_fields();
162 instance_size = Record::InstanceSize(num_fields);
163 break;
164 }
165#define SIZE_FROM_CLASS(clazz) case kTypedData##clazz##Cid:
167 const TypedDataPtr raw_obj = static_cast<const TypedDataPtr>(this);
168 intptr_t array_len = Smi::Value(raw_obj->untag()->length());
169 intptr_t lengthInBytes =
170 array_len * TypedData::ElementSizeInBytes(class_id);
171 instance_size = TypedData::InstanceSize(lengthInBytes);
172 break;
173 }
174#undef SIZE_FROM_CLASS
175 case kPointerCid:
176 instance_size = Pointer::InstanceSize();
177 break;
178 case kSuspendStateCid: {
179 const SuspendStatePtr raw_suspend_state =
180 static_cast<const SuspendStatePtr>(this);
181 intptr_t frame_capacity = raw_suspend_state->untag()->frame_capacity();
182 instance_size = SuspendState::InstanceSize(frame_capacity);
183 break;
184 }
185 case kTypeArgumentsCid: {
186 const TypeArgumentsPtr raw_array =
187 static_cast<const TypeArgumentsPtr>(this);
188 intptr_t array_length = Smi::Value(raw_array->untag()->length());
189 instance_size = TypeArguments::InstanceSize(array_length);
190 break;
191 }
192 case kPcDescriptorsCid: {
193 const PcDescriptorsPtr raw_descriptors =
194 static_cast<const PcDescriptorsPtr>(this);
195 intptr_t length = raw_descriptors->untag()->length_;
196 instance_size = PcDescriptors::InstanceSize(length);
197 break;
198 }
199 case kCodeSourceMapCid: {
200 const CodeSourceMapPtr raw_code_source_map =
201 static_cast<const CodeSourceMapPtr>(this);
202 intptr_t length = raw_code_source_map->untag()->length_;
203 instance_size = CodeSourceMap::InstanceSize(length);
204 break;
205 }
206 case kCompressedStackMapsCid: {
207 const CompressedStackMapsPtr maps =
208 static_cast<const CompressedStackMapsPtr>(this);
211 break;
212 }
213 case kLocalVarDescriptorsCid: {
214 const LocalVarDescriptorsPtr raw_descriptors =
215 static_cast<const LocalVarDescriptorsPtr>(this);
216 intptr_t num_descriptors = raw_descriptors->untag()->num_entries_;
217 instance_size = LocalVarDescriptors::InstanceSize(num_descriptors);
218 break;
219 }
220 case kExceptionHandlersCid: {
221 const ExceptionHandlersPtr raw_handlers =
222 static_cast<const ExceptionHandlersPtr>(this);
223 intptr_t num_handlers = raw_handlers->untag()->num_entries();
224 instance_size = ExceptionHandlers::InstanceSize(num_handlers);
225 break;
226 }
227 case kFreeListElement: {
229 FreeListElement* element = reinterpret_cast<FreeListElement*>(addr);
230 instance_size = element->HeapSize(tags);
231 break;
232 }
233 case kForwardingCorpse: {
235 ForwardingCorpse* element = reinterpret_cast<ForwardingCorpse*>(addr);
236 instance_size = element->HeapSize(tags);
237 break;
238 }
239 case kWeakSerializationReferenceCid: {
241 break;
242 }
243 default: {
244 // Get the (constant) instance size out of the class object.
245 // TODO(koda): Add Size(ClassTable*) interface to allow caching in loops.
246 auto isolate_group = IsolateGroup::Current();
247#if defined(DEBUG)
248 auto class_table = isolate_group->heap_walk_class_table();
249 if (!class_table->IsValidIndex(class_id) ||
250 !class_table->HasValidClassAt(class_id)) {
251 FATAL("Invalid cid: %" Pd ", obj: %p, tags: %x. Corrupt heap?",
252 class_id, this, static_cast<uint32_t>(tags));
253 }
254 ASSERT(class_table->SizeAt(class_id) > 0);
255#endif // DEBUG
256 instance_size = isolate_group->heap_walk_class_table()->SizeAt(class_id);
257 }
258 }
259 ASSERT(instance_size != 0);
260#if defined(DEBUG)
261 intptr_t tags_size = SizeTag::decode(tags);
262 if ((class_id == kArrayCid) && (instance_size > tags_size && tags_size > 0)) {
263 // TODO(22501): Array::MakeFixedLength could be in the process of shrinking
264 // the array (see comment therein), having already updated the tags but not
265 // yet set the new length. Wait a millisecond and try again.
266 int retries_remaining = 1000; // ... but not forever.
267 do {
268 OS::Sleep(1);
269 const ArrayPtr raw_array = static_cast<const ArrayPtr>(this);
270 intptr_t array_length = Smi::Value(raw_array->untag()->length());
271 instance_size = Array::InstanceSize(array_length);
272 } while ((instance_size > tags_size) && (--retries_remaining > 0));
273 }
274 if ((instance_size != tags_size) && (tags_size != 0)) {
275 FATAL("Size mismatch: %" Pd " from class vs %" Pd " from tags %" Px "\n",
276 instance_size, tags_size, tags);
277 }
278#endif // DEBUG
279 return instance_size;
280}
281
282intptr_t UntaggedObject::VisitPointersPredefined(ObjectPointerVisitor* visitor,
283 intptr_t class_id) {
284 ASSERT(class_id < kNumPredefinedCids);
285
286 intptr_t size = 0;
287
288 switch (class_id) {
289#define RAW_VISITPOINTERS(clazz) \
290 case k##clazz##Cid: { \
291 clazz##Ptr raw_obj = static_cast<clazz##Ptr>(this); \
292 size = Untagged##clazz::Visit##clazz##Pointers(raw_obj, visitor); \
293 break; \
294 }
296#undef RAW_VISITPOINTERS
297#define RAW_VISITPOINTERS(clazz) case kTypedData##clazz##Cid:
299 TypedDataPtr raw_obj = static_cast<TypedDataPtr>(this);
300 size = UntaggedTypedData::VisitTypedDataPointers(raw_obj, visitor);
301 break;
302 }
303#undef RAW_VISITPOINTERS
304#define RAW_VISITPOINTERS(clazz) case kExternalTypedData##clazz##Cid:
306 auto raw_obj = static_cast<ExternalTypedDataPtr>(this);
307 size = UntaggedExternalTypedData::VisitExternalTypedDataPointers(raw_obj,
308 visitor);
309 break;
310 }
311#undef RAW_VISITPOINTERS
312 case kByteDataViewCid:
314#define RAW_VISITPOINTERS(clazz) \
315 case kTypedData##clazz##ViewCid: \
316 case kUnmodifiableTypedData##clazz##ViewCid:
318 auto raw_obj = static_cast<TypedDataViewPtr>(this);
319 size =
320 UntaggedTypedDataView::VisitTypedDataViewPointers(raw_obj, visitor);
321 break;
322 }
323#undef RAW_VISITPOINTERS
324 case kByteBufferCid: {
325 InstancePtr raw_obj = static_cast<InstancePtr>(this);
326 size = UntaggedInstance::VisitInstancePointers(raw_obj, visitor);
327 break;
328 }
329#define RAW_VISITPOINTERS(clazz) case kFfi##clazz##Cid:
331 // NativeType do not have any fields or type arguments.
332 size = HeapSize();
333 break;
334 }
335#undef RAW_VISITPOINTERS
336 case kFreeListElement: {
338 FreeListElement* element = reinterpret_cast<FreeListElement*>(addr);
339 size = element->HeapSize();
340 break;
341 }
342 case kForwardingCorpse: {
344 ForwardingCorpse* forwarder = reinterpret_cast<ForwardingCorpse*>(addr);
345 size = forwarder->HeapSize();
346 break;
347 }
348 case kNullCid:
349 case kNeverCid:
350 size = HeapSize();
351 break;
352 default:
353 FATAL("Invalid cid: %" Pd ", obj: %p, tags: %x. Corrupt heap?", class_id,
354 this, static_cast<uint32_t>(tags_));
355 break;
356 }
357
358#if defined(DEBUG)
359 ASSERT(size != 0);
360 const intptr_t expected_size = HeapSize();
361
362 // In general we expect that visitors return exactly the same size that
363 // HeapSize would compute. However in case of Arrays we might have a
364 // discrepancy when concurrently visiting an array that is being shrunk with
365 // Array::MakeFixedLength: the visitor might have visited the full array while
366 // here we are observing a smaller HeapSize().
367 ASSERT(size == expected_size ||
368 (class_id == kArrayCid && size > expected_size));
369 return size; // Prefer larger size.
370#else
371 return size;
372#endif
373}
374
376 intptr_t class_id = GetClassId();
377 if ((class_id != kInstanceCid) && (class_id < kNumPredefinedCids)) {
378 VisitPointersPredefined(visitor, class_id);
379 return;
380 }
381
382 // N.B.: Not using the heap size!
383 uword next_field_offset = visitor->class_table()
384 ->At(class_id)
385 ->untag()
386 ->host_next_field_offset_in_words_
388 ASSERT(next_field_offset > 0);
389 uword obj_addr = UntaggedObject::ToAddr(this);
390 uword from = obj_addr + sizeof(UntaggedObject);
391 uword to = obj_addr + next_field_offset - kCompressedWordSize;
392 const auto first = reinterpret_cast<CompressedObjectPtr*>(from);
393 const auto last = reinterpret_cast<CompressedObjectPtr*>(to);
394
395 const auto unboxed_fields_bitmap =
396 visitor->class_table()->GetUnboxedFieldsMapAt(class_id);
397
398 if (!unboxed_fields_bitmap.IsEmpty()) {
399 intptr_t bit = sizeof(UntaggedObject) / kCompressedWordSize;
400 for (CompressedObjectPtr* current = first; current <= last; current++) {
401 if (!unboxed_fields_bitmap.Get(bit++)) {
402 visitor->VisitCompressedPointers(heap_base(), current, current);
403 }
404 }
405 } else {
406 visitor->VisitCompressedPointers(heap_base(), first, last);
407 }
408}
409
410// Most objects are visited with this function. It calls the from() and to()
411// methods on the raw object to get the first and last cells that need
412// visiting.
413#define REGULAR_VISITOR(Type) \
414 intptr_t Untagged##Type::Visit##Type##Pointers( \
415 Type##Ptr raw_obj, ObjectPointerVisitor* visitor) { \
416 /* Make sure that we got here with the tagged pointer as this. */ \
417 ASSERT(raw_obj->IsHeapObject()); \
418 ASSERT_UNCOMPRESSED(Type); \
419 visitor->VisitPointers(raw_obj->untag()->from(), raw_obj->untag()->to()); \
420 return Type::InstanceSize(); \
421 }
422
423#if !defined(DART_COMPRESSED_POINTERS)
424#define COMPRESSED_VISITOR(Type) REGULAR_VISITOR(Type)
425#else
426#define COMPRESSED_VISITOR(Type) \
427 intptr_t Untagged##Type::Visit##Type##Pointers( \
428 Type##Ptr raw_obj, ObjectPointerVisitor* visitor) { \
429 /* Make sure that we got here with the tagged pointer as this. */ \
430 ASSERT(raw_obj->IsHeapObject()); \
431 ASSERT_COMPRESSED(Type); \
432 visitor->VisitCompressedPointers(raw_obj->heap_base(), \
433 raw_obj->untag()->from(), \
434 raw_obj->untag()->to()); \
435 return Type::InstanceSize(); \
436 }
437#endif
438
439// It calls the from() and to() methods on the raw object to get the first and
440// last cells that need visiting.
441//
442// Though as opposed to Similar to [REGULAR_VISITOR] this visitor will call the
443// specialized VisitTypedDataViewPointers
444#define TYPED_DATA_VIEW_VISITOR(Type) \
445 intptr_t Untagged##Type::Visit##Type##Pointers( \
446 Type##Ptr raw_obj, ObjectPointerVisitor* visitor) { \
447 /* Make sure that we got here with the tagged pointer as this. */ \
448 ASSERT(raw_obj->IsHeapObject()); \
449 ASSERT_COMPRESSED(Type); \
450 visitor->VisitTypedDataViewPointers(raw_obj, raw_obj->untag()->from(), \
451 raw_obj->untag()->to()); \
452 return Type::InstanceSize(); \
453 }
454
455// For variable length objects. get_length is a code snippet that gets the
456// length of the object, which is passed to InstanceSize and the to() method.
457#define VARIABLE_VISITOR(Type, get_length) \
458 intptr_t Untagged##Type::Visit##Type##Pointers( \
459 Type##Ptr raw_obj, ObjectPointerVisitor* visitor) { \
460 /* Make sure that we got here with the tagged pointer as this. */ \
461 ASSERT(raw_obj->IsHeapObject()); \
462 intptr_t length = get_length; \
463 visitor->VisitPointers(raw_obj->untag()->from(), \
464 raw_obj->untag()->to(length)); \
465 return Type::InstanceSize(length); \
466 }
467
468#if !defined(DART_COMPRESSED_POINTERS)
469#define VARIABLE_COMPRESSED_VISITOR(Type, get_length) \
470 VARIABLE_VISITOR(Type, get_length)
471#else
472#define VARIABLE_COMPRESSED_VISITOR(Type, get_length) \
473 intptr_t Untagged##Type::Visit##Type##Pointers( \
474 Type##Ptr raw_obj, ObjectPointerVisitor* visitor) { \
475 /* Make sure that we got here with the tagged pointer as this. */ \
476 ASSERT(raw_obj->IsHeapObject()); \
477 intptr_t length = get_length; \
478 visitor->VisitCompressedPointers(raw_obj->heap_base(), \
479 raw_obj->untag()->from(), \
480 raw_obj->untag()->to(length)); \
481 return Type::InstanceSize(length); \
482 }
483#endif
484
485// For fixed-length objects that don't have any pointers that need visiting.
486#define NULL_VISITOR(Type) \
487 intptr_t Untagged##Type::Visit##Type##Pointers( \
488 Type##Ptr raw_obj, ObjectPointerVisitor* visitor) { \
489 /* Make sure that we got here with the tagged pointer as this. */ \
490 ASSERT(raw_obj->IsHeapObject()); \
491 ASSERT_NOTHING_TO_VISIT(Type); \
492 return Type::InstanceSize(); \
493 }
494
495// For objects that don't have any pointers that need visiting, but have a
496// variable length.
497#define VARIABLE_NULL_VISITOR(Type, get_length) \
498 intptr_t Untagged##Type::Visit##Type##Pointers( \
499 Type##Ptr raw_obj, ObjectPointerVisitor* visitor) { \
500 /* Make sure that we got here with the tagged pointer as this. */ \
501 ASSERT(raw_obj->IsHeapObject()); \
502 ASSERT_NOTHING_TO_VISIT(Type); \
503 intptr_t length = get_length; \
504 return Type::InstanceSize(length); \
505 }
506
507// For objects that are never instantiated on the heap.
508#define UNREACHABLE_VISITOR(Type) \
509 intptr_t Untagged##Type::Visit##Type##Pointers( \
510 Type##Ptr raw_obj, ObjectPointerVisitor* visitor) { \
511 UNREACHABLE(); \
512 return 0; \
513 }
514
516COMPRESSED_VISITOR(PatchClass)
517COMPRESSED_VISITOR(ClosureData)
518COMPRESSED_VISITOR(FfiTrampolineData)
519COMPRESSED_VISITOR(Script)
520COMPRESSED_VISITOR(Library)
521COMPRESSED_VISITOR(Namespace)
522COMPRESSED_VISITOR(KernelProgramInfo)
523COMPRESSED_VISITOR(WeakSerializationReference)
560 Smi::Value(raw_obj->untag()->length()))
563VARIABLE_COMPRESSED_VISITOR(Context, raw_obj->untag()->num_variables_)
566 TypedData,
567 TypedData::ElementSizeInBytes(raw_obj->GetClassId()) *
568 Smi::Value(raw_obj->untag()->length()))
569VARIABLE_COMPRESSED_VISITOR(ContextScope, raw_obj->untag()->num_variables_)
571 RecordShape(raw_obj->untag()->shape()).num_fields())
587VARIABLE_NULL_VISITOR(PcDescriptors, raw_obj->untag()->length_)
588VARIABLE_NULL_VISITOR(CodeSourceMap, raw_obj->untag()->length_)
590 CompressedStackMaps::PayloadSizeOf(raw_obj))
593// Abstract types don't have their visitor called.
603// Smi has no heap representation.
605
606intptr_t UntaggedField::VisitFieldPointers(FieldPtr raw_obj,
607 ObjectPointerVisitor* visitor) {
608 ASSERT(raw_obj->IsHeapObject());
610 visitor->VisitCompressedPointers(
611 raw_obj->heap_base(), raw_obj->untag()->from(), raw_obj->untag()->to());
612
613 if (visitor->trace_values_through_fields()) {
614 if (Field::StaticBit::decode(raw_obj->untag()->kind_bits_)) {
615 visitor->isolate_group()->ForEachIsolate(
616 [&](Isolate* isolate) {
617 intptr_t index =
618 Smi::Value(raw_obj->untag()->host_offset_or_field_id());
619 visitor->VisitPointer(&isolate->field_table()->table()[index]);
620 },
621 /*at_safepoint=*/true);
622 }
623 }
624 return Field::InstanceSize();
625}
626
627intptr_t UntaggedSuspendState::VisitSuspendStatePointers(
628 SuspendStatePtr raw_obj,
629 ObjectPointerVisitor* visitor) {
630 ASSERT(raw_obj->IsHeapObject());
631 ASSERT_COMPRESSED(SuspendState);
632
633 if (visitor->CanVisitSuspendStatePointers(raw_obj)) {
634 visitor->VisitCompressedPointers(
635 raw_obj->heap_base(), raw_obj->untag()->from(), raw_obj->untag()->to());
636
637 const uword pc = raw_obj->untag()->pc_;
638 if (pc != 0) {
639 Thread* thread = Thread::Current();
640 ASSERT(thread != nullptr);
641 ASSERT(thread->isolate_group() == visitor->isolate_group());
642 const uword sp = reinterpret_cast<uword>(raw_obj->untag()->payload());
643 StackFrame frame(thread);
644 frame.pc_ = pc;
645 frame.sp_ = sp;
646 frame.fp_ = sp + raw_obj->untag()->frame_size_;
647 frame.VisitObjectPointers(visitor);
648 }
649 }
650
651 return SuspendState::InstanceSize(raw_obj->untag()->frame_capacity());
652}
653
654bool UntaggedCode::ContainsPC(const ObjectPtr raw_obj, uword pc) {
655 if (!raw_obj->IsCode()) return false;
656 auto const raw_code = static_cast<const CodePtr>(raw_obj);
657 const uword start = Code::PayloadStartOf(raw_code);
658 const uword size = Code::PayloadSizeOf(raw_code);
659 return (pc - start) <= size; // pc may point just past last instruction.
660}
661
662intptr_t UntaggedCode::VisitCodePointers(CodePtr raw_obj,
663 ObjectPointerVisitor* visitor) {
664 visitor->VisitPointers(raw_obj->untag()->from(), raw_obj->untag()->to());
665
666 UntaggedCode* obj = raw_obj->untag();
667 intptr_t length = Code::PtrOffBits::decode(obj->state_bits_);
668#if defined(TARGET_ARCH_IA32)
669 // On IA32 only we embed pointers to objects directly in the generated
670 // instructions. The variable portion of a Code object describes where to
671 // find those pointers for tracing.
672 if (Code::AliveBit::decode(obj->state_bits_)) {
673 uword entry_point = Code::PayloadStartOf(raw_obj);
674 for (intptr_t i = 0; i < length; i++) {
675 int32_t offset = obj->data()[i];
676 visitor->VisitPointer(reinterpret_cast<ObjectPtr*>(entry_point + offset));
677 }
678 }
680#else
681 // On all other architectures, objects are referenced indirectly through
682 // either an ObjectPool or Thread.
683 ASSERT(length == 0);
684 return Code::InstanceSize(0);
685#endif
686}
687
688intptr_t UntaggedObjectPool::VisitObjectPoolPointers(
689 ObjectPoolPtr raw_obj,
690 ObjectPointerVisitor* visitor) {
691 const intptr_t length = raw_obj->untag()->length_;
692 UntaggedObjectPool::Entry* entries = raw_obj->untag()->data();
693 uint8_t* entry_bits = raw_obj->untag()->entry_bits();
694 for (intptr_t i = 0; i < length; ++i) {
695 ObjectPool::EntryType entry_type =
696 ObjectPool::TypeBits::decode(entry_bits[i]);
697 if (entry_type == ObjectPool::EntryType::kTaggedObject) {
698 visitor->VisitPointer(&entries[i].raw_obj_);
699 }
700 }
702}
703
704bool UntaggedInstructions::ContainsPC(const InstructionsPtr raw_instr,
705 uword pc) {
706 const uword start = Instructions::PayloadStart(raw_instr);
707 const uword size = Instructions::Size(raw_instr);
708 // We use <= instead of < here because the saved-pc can be outside the
709 // instruction stream if the last instruction is a call we don't expect to
710 // return (e.g. because it throws an exception).
711 return (pc - start) <= size;
712}
713
714intptr_t UntaggedInstance::VisitInstancePointers(
715 InstancePtr raw_obj,
716 ObjectPointerVisitor* visitor) {
717 // Make sure that we got here with the tagged pointer as this.
718 ASSERT(raw_obj->IsHeapObject());
719 uword tags = raw_obj->untag()->tags_;
720 intptr_t instance_size = SizeTag::decode(tags);
721 if (instance_size == 0) {
722 instance_size = visitor->class_table()->SizeAt(raw_obj->GetClassId());
723 }
724
725 // Calculate the first and last raw object pointer fields.
726 uword obj_addr = UntaggedObject::ToAddr(raw_obj);
727 uword from = obj_addr + sizeof(UntaggedObject);
728 uword to = obj_addr + instance_size - kCompressedWordSize;
729 visitor->VisitCompressedPointers(raw_obj->heap_base(),
730 reinterpret_cast<CompressedObjectPtr*>(from),
731 reinterpret_cast<CompressedObjectPtr*>(to));
732 return instance_size;
733}
734
735intptr_t UntaggedImmutableArray::VisitImmutableArrayPointers(
736 ImmutableArrayPtr raw_obj,
737 ObjectPointerVisitor* visitor) {
738 return UntaggedArray::VisitArrayPointers(raw_obj, visitor);
739}
740
741intptr_t UntaggedConstMap::VisitConstMapPointers(
742 ConstMapPtr raw_obj,
743 ObjectPointerVisitor* visitor) {
744 return UntaggedMap::VisitMapPointers(raw_obj, visitor);
745}
746
747intptr_t UntaggedConstSet::VisitConstSetPointers(
748 ConstSetPtr raw_obj,
749 ObjectPointerVisitor* visitor) {
750 return UntaggedSet::VisitSetPointers(raw_obj, visitor);
751}
752
753void UntaggedObject::RememberCard(ObjectPtr const* slot) {
754 Page::Of(static_cast<ObjectPtr>(this))->RememberCard(slot);
755}
756
757#if defined(DART_COMPRESSED_POINTERS)
758void UntaggedObject::RememberCard(CompressedObjectPtr const* slot) {
759 Page::Of(static_cast<ObjectPtr>(this))->RememberCard(slot);
760}
761#endif
762
764 RememberCard,
765 2,
766 uword /*ObjectPtr*/ object_in,
767 ObjectPtr* slot) {
768 ObjectPtr object = static_cast<ObjectPtr>(object_in);
769 ASSERT(object->IsOldObject());
770 ASSERT(object->untag()->IsCardRemembered());
771 Page::Of(object)->RememberCard(slot);
772}
774
776 switch (k) {
777#define ENUM_CASE(name, init) \
778 case Kind::k##name: \
779 return #name;
781#undef ENUM_CASE
782 default:
783 return nullptr;
784 }
785}
786
787bool UntaggedPcDescriptors::ParseKind(const char* cstr, Kind* out) {
788 ASSERT(cstr != nullptr && out != nullptr);
789#define ENUM_CASE(name, init) \
790 if (strcmp(#name, cstr) == 0) { \
791 *out = Kind::k##name; \
792 return true; \
793 }
795#undef ENUM_CASE
796 return false;
797}
798#undef PREFIXED_NAME
799
800} // namespace dart
#define CLASS_LIST_NO_OBJECT(V)
Definition class_id.h:201
#define CLASS_LIST_FFI_TYPE_MARKER(V)
Definition class_id.h:165
#define CLASS_LIST_TYPED_DATA(V)
Definition class_id.h:137
static intptr_t InstanceSize()
Definition object.h:10910
static constexpr bool decode(uword value)
Definition bitfield.h:173
ClassPtr At(intptr_t cid) const
bool IsValidIndex(intptr_t cid) const
UnboxedFieldBitmap GetUnboxedFieldsMapAt(intptr_t cid) const
bool HasValidClassAt(intptr_t cid) const
static intptr_t InstanceSize()
Definition object.h:6202
static uword PayloadSizeOf(const CodePtr code)
Definition object.h:6877
static intptr_t InstanceSize()
Definition object.h:7134
static uword PayloadStartOf(const CodePtr code)
Definition object.h:6824
static intptr_t InstanceSize()
Definition object.h:6272
static uintptr_t PayloadSizeOf(const CompressedStackMapsPtr raw)
Definition object.h:6243
static intptr_t InstanceSize()
Definition object.h:7506
static intptr_t InstanceSize()
Definition object.h:7419
static IsolateGroup * vm_isolate_group()
Definition dart.h:69
static intptr_t InstanceSize()
Definition object.h:6579
ObjectPtr * table()
Definition field_table.h:42
static intptr_t InstanceSize()
Definition object.h:4531
@ kNew
Definition heap.h:38
static intptr_t InstanceSize()
Definition object.h:5906
static intptr_t Size(const InstructionsSectionPtr instr)
Definition object.h:5903
static intptr_t InstanceSize()
Definition object.h:5804
uword PayloadStart() const
Definition object.h:5716
intptr_t Size() const
Definition object.h:5711
Heap * heap() const
Definition isolate.h:295
static IsolateGroup * Current()
Definition isolate.h:534
ClassTable * class_table() const
Definition isolate.h:491
FieldTable * field_table() const
Definition isolate.h:953
static intptr_t InstanceSize()
Definition object.h:6026
static void Sleep(int64_t millis)
const ClassTable * class_table() const
Definition visitor.h:71
void VisitCompressedPointers(uword heap_base, CompressedObjectPtr *first, CompressedObjectPtr *last)
Definition visitor.h:43
compiler::ObjectPoolBuilderEntry::EntryType EntryType
Definition object.h:5523
static intptr_t InstanceSize()
Definition object.h:5620
void Validate(IsolateGroup *isolate_group) const
Definition raw_object.cc:30
UntaggedObject * untag() const
static intptr_t InstanceSize()
Definition object.h:10543
static Page * Of(ObjectPtr obj)
Definition page.h:141
void RememberCard(ObjectPtr const *slot)
Definition page.h:162
static intptr_t InstanceSize()
Definition object.h:6060
static intptr_t InstanceSize()
Definition object.h:11861
static intptr_t InstanceSize()
Definition object.h:11434
intptr_t Value() const
Definition object.h:9969
static intptr_t InstanceSize()
Definition object.h:12600
static Thread * Current()
Definition thread.h:361
static intptr_t InstanceSize()
Definition object.h:10683
static intptr_t InstanceSize()
Definition object.h:8962
intptr_t ElementSizeInBytes() const
Definition object.h:11505
static intptr_t InstanceSize()
Definition object.h:11647
static constexpr uword decode(uword tag)
Definition raw_object.h:205
uword tags() const
Definition raw_object.h:294
void Validate(IsolateGroup *isolate_group) const
Definition raw_object.cc:42
bool IsCardRemembered() const
Definition raw_object.h:364
static uword ToAddr(const UntaggedObject *raw_obj)
Definition raw_object.h:501
bool IsOldObject() const
Definition raw_object.h:289
intptr_t HeapSize() const
Definition raw_object.h:380
bool IsMarked() const
Definition raw_object.h:299
bool InVMIsolateHeap() const
Definition raw_object.cc:20
void VisitPointersPrecise(ObjectPointerVisitor *visitor)
bool IsNewObject() const
Definition raw_object.h:284
uword heap_base() const
Definition raw_object.h:569
intptr_t GetClassId() const
Definition raw_object.h:371
friend class FreeListElement
Definition raw_object.h:793
static const char * KindToCString(Kind k)
static bool ParseKind(const char *cstr, Kind *out)
static intptr_t InstanceSize()
Definition object.h:6715
static intptr_t InstanceSize()
Definition object.h:6652
#define ASSERT(E)
double frame
Definition examples.cpp:31
#define FATAL(error)
size_t length
static constexpr intptr_t kCompressedWordSizeLog2
Definition globals.h:43
@ kForwardingCorpse
Definition class_id.h:225
@ kNullCid
Definition class_id.h:252
@ kNumPredefinedCids
Definition class_id.h:257
@ kByteDataViewCid
Definition class_id.h:244
@ kByteBufferCid
Definition class_id.h:247
@ kNeverCid
Definition class_id.h:255
@ kFreeListElement
Definition class_id.h:224
@ kUnmodifiableByteDataViewCid
Definition class_id.h:245
@ kHeapObjectTag
uintptr_t uword
Definition globals.h:501
static constexpr intptr_t kCompressedWordSize
Definition globals.h:42
raw_obj untag() -> num_entries()) VARIABLE_COMPRESSED_VISITOR(Array, Smi::Value(raw_obj->untag() ->length())) VARIABLE_COMPRESSED_VISITOR(TypedData, TypedData::ElementSizeInBytes(raw_obj->GetClassId()) *Smi::Value(raw_obj->untag() ->length())) VARIABLE_COMPRESSED_VISITOR(Record, RecordShape(raw_obj->untag() ->shape()).num_fields()) VARIABLE_NULL_VISITOR(CompressedStackMaps, CompressedStackMaps::PayloadSizeOf(raw_obj)) VARIABLE_NULL_VISITOR(OneByteString, Smi::Value(raw_obj->untag() ->length())) VARIABLE_NULL_VISITOR(TwoByteString, Smi::Value(raw_obj->untag() ->length())) intptr_t UntaggedField::VisitFieldPointers(FieldPtr raw_obj, ObjectPointerVisitor *visitor)
ObjectPtr CompressedObjectPtr
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
#define Px
Definition globals.h:410
#define Pd
Definition globals.h:408
#define SIZE_FROM_CLASS(clazz)
#define TYPED_DATA_VIEW_VISITOR(Type)
#define COMPRESSED_VISITOR(Type)
#define VARIABLE_COMPRESSED_VISITOR(Type, get_length)
#define REGULAR_VISITOR(Type)
#define ENUM_CASE(name, init)
#define RAW_VISITPOINTERS(clazz)
#define NULL_VISITOR(Type)
#define UNREACHABLE_VISITOR(Type)
#define VARIABLE_NULL_VISITOR(Type, get_length)
#define FOR_EACH_RAW_PC_DESCRIPTOR(V)
#define ASSERT_COMPRESSED(Type)
Definition raw_object.h:117
#define END_LEAF_RUNTIME_ENTRY
#define DEFINE_LEAF_RUNTIME_ENTRY(type, name, argument_count,...)
Point offset