1// Copyright (c) 2020, 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/field_table.h"
6
7#include "platform/atomic.h"
8#include "vm/flags.h"
9#include "vm/growable_array.h"
10#include "vm/heap/heap.h"
11#include "vm/object.h"
12#include "vm/object_graph.h"
13#include "vm/object_store.h"
14#include "vm/raw_object.h"
15#include "vm/visitor.h"
16
17namespace dart {
18
19FieldTable::~FieldTable() {
20 FreeOldTables();
21 delete old_tables_; // Allocated in FieldTable::FieldTable()
22 free(table_); // Allocated in FieldTable::Grow()
23}
24
25void FieldTable::FreeOldTables() {
26 while (old_tables_->length() > 0) {
27 free(old_tables_->RemoveLast());
28 }
29}
30
31intptr_t FieldTable::FieldOffsetFor(intptr_t field_id) {
32 return field_id * sizeof(InstancePtr); // NOLINT
33}
34
35void FieldTable::Register(const Field& field) {
36 ASSERT(Thread::Current()->IsMutatorThread());
37 if (free_head_ < 0) {
38 if (top_ == capacity_) {
39 const intptr_t new_capacity = capacity_ + kCapacityIncrement;
40 Grow(new_capacity);
41 }
42
43 ASSERT(top_ < capacity_);
44
45 field.set_field_id(top_);
46 table_[top_] = Object::sentinel().raw();
47
48 ++top_;
49 return;
50 }
51
52 // Reuse existing free element. This is "slow path" that should only be
53 // triggered after hot reload.
54 intptr_t reused_free = free_head_;
55 free_head_ = Smi::Value(Smi::RawCast(table_[free_head_]));
56 field.set_field_id(reused_free);
57 table_[reused_free] = Object::sentinel().raw();
58}
59
60void FieldTable::Free(intptr_t field_id) {
61 table_[field_id] = Smi::New(free_head_);
62 free_head_ = field_id;
63}
64
65void FieldTable::SetAt(intptr_t index, InstancePtr raw_instance) {
66 ASSERT(index < capacity_);
67 table_[index] = raw_instance;
68}
69
70void FieldTable::AllocateIndex(intptr_t index) {
71 if (index >= capacity_) {
72 const intptr_t new_capacity = index + kCapacityIncrement;
73 Grow(new_capacity);
74 }
75
76 ASSERT(table_[index] == nullptr);
77 if (index >= top_) {
78 top_ = index + 1;
79 }
80}
81
82void FieldTable::Grow(intptr_t new_capacity) {
83 ASSERT(new_capacity > capacity_);
84
85 auto old_table = table_;
86 auto new_table = static_cast<InstancePtr*>(
87 malloc(new_capacity * sizeof(InstancePtr))); // NOLINT
88 intptr_t i;
89 for (i = 0; i < top_; i++) {
90 new_table[i] = old_table[i];
91 }
92 for (; i < new_capacity; i++) {
93 new_table[i] = InstancePtr();
94 }
95 capacity_ = new_capacity;
96 old_tables_->Add(old_table);
97 // Ensure that new_table_ is populated before it is published
98 // via store to table_.
99 std::atomic_thread_fence(std::memory_order_release);
100 table_ = new_table;
101 Thread::Current()->field_table_values_ = table_;
102}
103
104FieldTable* FieldTable::Clone() {
105 FieldTable* clone = new FieldTable();
106 auto new_table = static_cast<InstancePtr*>(
107 malloc(capacity_ * sizeof(InstancePtr))); // NOLINT
108 memmove(new_table, table_, top_ * sizeof(InstancePtr));
109 ASSERT(clone->table_ == nullptr);
110 clone->table_ = new_table;
111 clone->capacity_ = capacity_;
112 clone->top_ = top_;
113 return clone;
114}
115
116void FieldTable::VisitObjectPointers(ObjectPointerVisitor* visitor) {
117 // GC might try to visit field table before it's isolate done setting it up.
118 if (table_ == nullptr) {
119 return;
120 }
121
122 ASSERT(visitor != NULL);
123 visitor->set_gc_root_type("static fields table");
124 visitor->VisitPointers(reinterpret_cast<ObjectPtr*>(&table_[0]),
125 reinterpret_cast<ObjectPtr*>(&table_[top_ - 1]));
126 visitor->clear_gc_root_type();
127}
128
129} // namespace dart
130