// 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()), 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*>(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* 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_