| // Copyright (c) 2020, 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. |
| |
| #ifndef RUNTIME_VM_FIELD_TABLE_H_ |
| #define RUNTIME_VM_FIELD_TABLE_H_ |
| |
| #include "platform/assert.h" |
| #include "platform/atomic.h" |
| |
| #include "vm/bitfield.h" |
| #include "vm/class_id.h" |
| #include "vm/globals.h" |
| #include "vm/growable_array.h" |
| #include "vm/tagged_pointer.h" |
| |
| namespace dart { |
| |
| class Isolate; |
| class Field; |
| class FieldInvalidator; |
| |
| class FieldTable { |
| public: |
| explicit FieldTable(Isolate* isolate) |
| : top_(0), |
| capacity_(0), |
| free_head_(-1), |
| table_(nullptr), |
| old_tables_(new MallocGrowableArray<ObjectPtr*>()), |
| isolate_(isolate), |
| is_ready_to_use_(isolate == nullptr) {} |
| |
| ~FieldTable(); |
| |
| bool IsReadyToUse() const; |
| void MarkReadyToUse(); |
| |
| intptr_t NumFieldIds() const { return top_; } |
| intptr_t Capacity() const { return capacity_; } |
| |
| ObjectPtr* table() { return table_; } |
| |
| void FreeOldTables(); |
| |
| // Used by the generated code. |
| static intptr_t FieldOffsetFor(intptr_t field_id); |
| |
| bool IsValidIndex(intptr_t index) const { return index >= 0 && index < top_; } |
| |
| // Returns whether registering this field caused a growth in the backing |
| // store. |
| bool Register(const Field& field, intptr_t expected_field_id = -1); |
| void AllocateIndex(intptr_t index); |
| |
| // Static field elements are being freed only during isolate reload |
| // when initially created static field have to get remapped to point |
| // to an existing static field value. |
| void Free(intptr_t index); |
| |
| ObjectPtr At(intptr_t index, bool concurrent_use = false) const { |
| ASSERT(IsValidIndex(index)); |
| if (concurrent_use) { |
| ObjectPtr* table = |
| reinterpret_cast<const AcqRelAtomic<ObjectPtr*>*>(&table_)->load(); |
| return reinterpret_cast<AcqRelAtomic<ObjectPtr>*>(&table[index])->load(); |
| } else { |
| // There is no concurrent access expected for this field, so we avoid |
| // using atomics. This will allow us to detect via TSAN if there are |
| // racy uses. |
| return table_[index]; |
| } |
| } |
| |
| void SetAt(intptr_t index, |
| ObjectPtr raw_instance, |
| bool concurrent_use = false) { |
| ASSERT(index < capacity_); |
| ObjectPtr* slot = &table_[index]; |
| if (concurrent_use) { |
| reinterpret_cast<AcqRelAtomic<ObjectPtr>*>(slot)->store(raw_instance); |
| } else { |
| // There is no concurrent access expected for this field, so we avoid |
| // using atomics. This will allow us to detect via TSAN if there are |
| // racy uses. |
| *slot = raw_instance; |
| } |
| } |
| |
| FieldTable* Clone(Isolate* for_isolate); |
| |
| void VisitObjectPointers(ObjectPointerVisitor* visitor); |
| |
| static const int kInitialCapacity = 512; |
| static const int kCapacityIncrement = 256; |
| |
| private: |
| friend class GCMarker; |
| friend class MarkingWeakVisitor; |
| friend class Scavenger; |
| friend class ScavengerWeakVisitor; |
| |
| void Grow(intptr_t new_capacity); |
| |
| intptr_t top_; |
| intptr_t capacity_; |
| // -1 if free list is empty, otherwise index of first empty element. Empty |
| // elements are organized into linked list - they contain index of next |
| // element, last element contains -1. |
| intptr_t free_head_; |
| |
| ObjectPtr* table_; |
| // When table_ grows and have to reallocated, keep the old one here |
| // so it will get freed when its are no longer in use. |
| MallocGrowableArray<ObjectPtr*>* old_tables_; |
| |
| // If non-NULL, it will specify the isolate this field table belongs to. |
| // Growing the field table will keep the cached field table on the isolate's |
| // mutator thread up-to-date. |
| Isolate* isolate_; |
| |
| // Whether this field table is ready to use by e.g. registering new static |
| // fields. |
| bool is_ready_to_use_ = false; |
| |
| DISALLOW_COPY_AND_ASSIGN(FieldTable); |
| }; |
| |
| } // namespace dart |
| |
| #endif // RUNTIME_VM_FIELD_TABLE_H_ |