Flutter Engine
The Flutter Engine
port_set.h
Go to the documentation of this file.
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#ifndef RUNTIME_VM_PORT_SET_H_
6#define RUNTIME_VM_PORT_SET_H_
7
8#include "include/dart_api.h"
9
10#include "platform/allocation.h"
11#include "platform/globals.h"
12#include "platform/utils.h"
13
14namespace dart {
15
16template <typename T /* :public PortSet<T>::Entry */>
17class PortSet {
18 public:
19 static constexpr Dart_Port kFreePort = static_cast<Dart_Port>(0);
20 static constexpr Dart_Port kDeletedPort = static_cast<Dart_Port>(3);
21
22 struct Entry : public MallocAllocated {
24
25 // Free entries have set this to 0.
27 };
28
29 class Iterator {
30 public:
31 Iterator(PortSet<T>* ports, intptr_t index) : ports_(ports), index_(index) {
32#if defined(DEBUG)
33 dirty_counter_ = ports_->dirty_counter_;
34#endif
35 }
36
37 DART_FORCE_INLINE T& operator->() const {
38 ASSERT(index_ >= 0 && index_ < ports_->capacity_);
39 DEBUG_ASSERT(!WasModified());
40 return ports_->map_[index_];
41 }
42 DART_FORCE_INLINE T& operator*() const {
43 ASSERT(index_ >= 0 && index_ < ports_->capacity_);
44 DEBUG_ASSERT(!WasModified());
45 return ports_->map_[index_];
46 }
47
48 DART_FORCE_INLINE bool operator==(const Iterator& other) const {
49 DEBUG_ASSERT(!WasModified());
50 return ports_ == other.ports_ && index_ == other.index_;
51 }
52
53 DART_FORCE_INLINE bool operator!=(const Iterator& other) const {
54 DEBUG_ASSERT(!WasModified());
55 return !(*this == other);
56 }
57
58 DART_FORCE_INLINE Iterator& operator++() {
59 DEBUG_ASSERT(!WasModified());
60 index_++;
61 while (index_ < ports_->capacity_) {
62 const Dart_Port port = ports_->map_[index_].port;
63 if (port == kFreePort || port == kDeletedPort) {
64 index_++;
65 continue;
66 } else {
67 break;
68 }
69 }
70 return *this;
71 }
72
73 // The caller must ensure to call [PortSet::Rebalance] once the iterator is
74 // not used anymore.
75 DART_FORCE_INLINE void Delete() {
76 DEBUG_ASSERT(!WasModified());
77 ports_->map_[index_] = T();
78 ports_->map_[index_].port = kDeletedPort;
79 ports_->used_--;
80 ports_->deleted_++;
81 }
82
83 private:
84 friend class PortSet;
85
86#if defined(DEBUG)
87 // Whether the underlying [PortSet] was modified in a way that would render
88 // the iterator unusable.
89 bool WasModified() const {
90 return dirty_counter_ != ports_->dirty_counter_;
91 }
92#endif
93
94 PortSet<T>* ports_;
95 intptr_t index_ = 0;
96#if defined(DEBUG)
97 intptr_t dirty_counter_ = 0;
98#endif
99 };
100
102 const intptr_t kInitialCapacity = 8;
103 ASSERT(Utils::IsPowerOfTwo(kInitialCapacity));
104 map_ = new T[kInitialCapacity];
105 capacity_ = kInitialCapacity;
106 }
108 delete[] map_;
109 map_ = nullptr;
110 }
111
112 bool IsEmpty() const { return used_ == 0; }
113
114 DART_FORCE_INLINE Iterator begin() {
115 for (intptr_t i = 0; i < capacity_; ++i) {
116 auto& entry = map_[i];
117 if (entry.port != kFreePort && entry.port != kDeletedPort) {
118 return Iterator(this, i);
119 }
120 }
121 return end();
122 }
123
124 DART_FORCE_INLINE Iterator end() { return Iterator(this, capacity_); }
125
126 void Insert(const T& entry) {
127 // Search for the first unused slot. Make use of the knowledge that here is
128 // currently no port with this id in the port map.
129 ASSERT(FindIndexOfPort(entry.port) < 0);
130 intptr_t index = entry.port % capacity_;
131 T cur = map_[index];
132
133 // Stop the search at the first found unused (free or deleted) slot.
134 while (cur.port != kFreePort && cur.port != kDeletedPort) {
135 index = (index + 1) % capacity_;
136 cur = map_[index];
137 }
138
139 // Insert the newly created port at the index.
140 ASSERT(map_[index].port == kFreePort || map_[index].port == kDeletedPort);
141 if (map_[index].port == kDeletedPort) {
142 deleted_--;
143 }
144 map_[index] = entry;
145 ASSERT(FindIndexOfPort(entry.port) >= 0);
146
147 // Increment number of used slots and grow if necessary.
148 used_++;
149 MaintainInvariants();
150
151#if defined(DEBUG)
152 dirty_counter_++;
153#endif
154 }
155
157 const intptr_t index = FindIndexOfPort(port);
158 if (index >= 0) return Iterator(this, index);
159 return Iterator(this, capacity_);
160 }
161
162 bool Contains(Dart_Port port) { return FindIndexOfPort(port) >= 0; }
163
164 // To be called if an iterator was used to delete an entry.
165 void Rebalance() { MaintainInvariants(); }
166
167 private:
168 intptr_t FindIndexOfPort(Dart_Port port) {
169 // ILLEGAL_PORT (0) is used as a sentinel value in Entry.port. The loop
170 // below could return the index to a deleted port when we are searching for
171 // port id ILLEGAL_PORT. Return -1 immediately to indicate the port
172 // does not exist.
173 if (port == ILLEGAL_PORT) {
174 return -1;
175 }
177 intptr_t index = port % capacity_;
178 intptr_t start_index = index;
179 T entry = map_[index];
180 while (entry.port != kFreePort) {
181 if (entry.port == port) {
182 return index;
183 }
184 index = (index + 1) % capacity_;
185 // Prevent endless loops.
186 ASSERT(index != start_index);
187 entry = map_[index];
188 }
189 return -1;
190 }
191
192 void MaintainInvariants() {
193 const intptr_t empty = capacity_ - used_ - deleted_;
194 if (used_ > ((capacity_ / 4) * 3)) {
195 // Grow the port map.
196 Rehash(capacity_ * 2);
197 } else if (empty < deleted_) {
198 // Rehash without growing the table to flush the deleted slots out of the
199 // map.
200 Rehash(capacity_);
201 }
202 }
203
204 void Rehash(intptr_t new_capacity) {
205 T* new_ports = new T[new_capacity];
206
207 for (auto entry : *this) {
208 intptr_t new_index = entry.port % new_capacity;
209 while (new_ports[new_index].port != 0) {
210 new_index = (new_index + 1) % new_capacity;
211 }
212 new_ports[new_index] = entry;
213 }
214 delete[] map_;
215 map_ = new_ports;
216 capacity_ = new_capacity;
217 deleted_ = 0;
218
219#if defined(DEBUG)
220 dirty_counter_++;
221#endif
222 }
223
224 T* map_ = nullptr;
225 intptr_t capacity_ = 0;
226 intptr_t used_ = 0;
227 intptr_t deleted_ = 0;
228
229#if defined(DEBUG)
230 intptr_t dirty_counter_ = 0;
231#endif
232};
233
234} // namespace dart
235
236#endif // RUNTIME_VM_PORT_SET_H_
#define DEBUG_ASSERT(cond)
Definition: assert.h:321
DART_FORCE_INLINE bool operator==(const Iterator &other) const
Definition: port_set.h:48
DART_FORCE_INLINE T & operator*() const
Definition: port_set.h:42
DART_FORCE_INLINE Iterator & operator++()
Definition: port_set.h:58
DART_FORCE_INLINE void Delete()
Definition: port_set.h:75
Iterator(PortSet< T > *ports, intptr_t index)
Definition: port_set.h:31
DART_FORCE_INLINE bool operator!=(const Iterator &other) const
Definition: port_set.h:53
DART_FORCE_INLINE T & operator->() const
Definition: port_set.h:37
void Insert(const T &entry)
Definition: port_set.h:126
static constexpr Dart_Port kDeletedPort
Definition: port_set.h:20
Iterator TryLookup(Dart_Port port)
Definition: port_set.h:156
DART_FORCE_INLINE Iterator begin()
Definition: port_set.h:114
DART_FORCE_INLINE Iterator end()
Definition: port_set.h:124
void Rebalance()
Definition: port_set.h:165
bool IsEmpty() const
Definition: port_set.h:112
bool Contains(Dart_Port port)
Definition: port_set.h:162
static constexpr Dart_Port kFreePort
Definition: port_set.h:19
static constexpr bool IsPowerOfTwo(T x)
Definition: utils.h:76
#define ILLEGAL_PORT
Definition: dart_api.h:1535
int64_t Dart_Port
Definition: dart_api.h:1525
#define ASSERT(E)
EMSCRIPTEN_KEEPALIVE void empty()
Definition: dart_vm.cc:33
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service port
Definition: switches.h:87
#define T
Definition: precompiler.cc:65
Dart_Port port
Definition: port_set.h:26