| // 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, IsolateGroup* isolate_group = nullptr) | |
| : top_(0), | |
| capacity_(0), | |
| free_head_(-1), | |
| table_(nullptr), | |
| old_tables_(new MallocGrowableArray<ObjectPtr*>()), | |
| isolate_(isolate), | |
| isolate_group_(isolate_group), | |
| 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 = | |
| std::atomic_ref(table_).load(std::memory_order::acquire); | |
| return std::atomic_ref(table[index]).load(std::memory_order_acquire); | |
| } 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, | |
| IsolateGroup* for_isolate_group = nullptr); | |
| void VisitObjectPointers(ObjectPointerVisitor* visitor); | |
| static constexpr int kInitialCapacity = 512; | |
| static constexpr int kCapacityIncrement = 256; | |
| private: | |
| 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_; | |
| // Mutable for atomic_ref in At. | |
| mutable 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_; | |
| IsolateGroup* isolate_group_; | |
| // 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_ |