Flutter Engine
The Flutter Engine
closure_functions_cache.cc
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
6
8#include "vm/hash_table.h"
9#include "vm/object.h"
10#include "vm/object_store.h"
11
12namespace dart {
13
15 public:
16 static const char* Name() { return "FunctionMapTraits"; }
17 static bool ReportStats() { return false; }
18 static bool IsMatch(const Object& a, const Object& b) {
19 return a.ptr() == b.ptr();
20 }
21 static uword Hash(const Object& key) { return Function::Cast(key).Hash(); }
22};
23
25
27 const Function& member_function,
28 intptr_t kernel_offset) {
29 auto thread = Thread::Current();
30 SafepointReadRwLocker ml(thread, thread->isolate_group()->program_lock());
31 return LookupClosureFunctionLocked(member_function, kernel_offset);
32}
33
35 const Function& member_function,
36 intptr_t kernel_offset) {
37 auto thread = Thread::Current();
38 auto zone = thread->zone();
39 auto object_store = thread->isolate_group()->object_store();
40
42 thread->isolate_group()->program_lock()->IsCurrentThreadReader());
43
44 auto& map_array =
45 Array::Handle(zone, object_store->closure_functions_table());
46 if (map_array.IsNull()) {
47 return Function::null();
48 }
49
50 FunctionHashMap map(zone, map_array.ptr());
51 map_array ^= map.GetOrNull(member_function);
52 map.Release();
53
54 if (map_array.IsNull()) {
55 return Function::null();
56 }
57
58 auto& result = Function::Handle(zone);
59 IntHashMap map2(zone, map_array.ptr());
60 result ^= map2.GetOrNull(Smi::Handle(zone, Smi::New(kernel_offset)));
61 map2.Release();
62
63 return result.ptr();
64}
65
67 const Function& function,
68 bool allow_implicit_closure_functions /* = false */) {
70
71 auto thread = Thread::Current();
72 auto zone = thread->zone();
73 auto object_store = thread->isolate_group()->object_store();
74
76 thread->isolate_group()->program_lock()->IsCurrentThreadWriter());
77
78 auto& closures =
79 GrowableObjectArray::Handle(zone, object_store->closure_functions());
80 if (closures.IsNull()) {
81 closures = GrowableObjectArray::New();
82 object_store->set_closure_functions(closures);
83 }
84
85 ASSERT(allow_implicit_closure_functions ||
86 function.IsNonImplicitClosureFunction());
87 closures.Add(function, Heap::kOld);
88
89 if (allow_implicit_closure_functions) {
90 return;
91 }
92
93 const Function& member_function =
94 Function::Handle(zone, function.GetOutermostFunction());
95 ASSERT(function.kernel_offset() > 0);
96
97 auto& map_array =
98 Array::Handle(zone, object_store->closure_functions_table());
99 if (map_array.IsNull()) {
100 map_array = HashTables::New<FunctionHashMap>(16, Heap::kOld);
101 }
102 FunctionHashMap map(zone, map_array.ptr());
103 map_array ^= map.GetOrNull(member_function);
104 if (map_array.IsNull()) {
105 map_array = HashTables::New<IntHashMap>(4, Heap::kOld);
106 }
107 IntHashMap map2(zone, map_array.ptr());
108 map2.UpdateOrInsert(Smi::Handle(zone, Smi::New(function.kernel_offset())),
109 function);
110 map.UpdateOrInsert(member_function, map2.Release());
111 object_store->set_closure_functions_table(map.Release());
112}
113
115 auto thread = Thread::Current();
116 auto zone = thread->zone();
117 auto object_store = thread->isolate_group()->object_store();
118
119 SafepointReadRwLocker ml(thread, thread->isolate_group()->program_lock());
120
121 const auto& closures_array =
122 GrowableObjectArray::Handle(zone, object_store->closure_functions());
123 if (!closures_array.IsNull()) {
124 intptr_t num_closures = closures_array.Length();
125 for (intptr_t i = 0; i < num_closures; i++) {
126 if (closures_array.At(i) == needle.ptr()) {
127 return i;
128 }
129 }
130 }
131 return -1;
132}
133
135 auto thread = Thread::Current();
136 auto zone = thread->zone();
137 auto object_store = thread->isolate_group()->object_store();
138
139 SafepointReadRwLocker ml(thread, thread->isolate_group()->program_lock());
140
141 const auto& closures_array =
142 GrowableObjectArray::Handle(zone, object_store->closure_functions());
143 if (idx < 0 || closures_array.IsNull() || idx >= closures_array.Length()) {
144 return Function::null();
145 }
146 return Function::RawCast(closures_array.At(idx));
147}
148
150 std::function<bool(const Function&)> callback) {
151 auto thread = Thread::Current();
152 auto zone = thread->zone();
153 auto object_store = thread->isolate_group()->object_store();
154
155 auto& current_data = Array::Handle(zone);
156 auto& entry = Function::Handle(zone);
157
158 // NOTE: Inner functions may get added to the closures array while iterating -
159 // we guarantee that any closure functions added on this thread by a
160 // [callback] call will be visited as well.
161 //
162 // We avoid holding a lock while accessing the closures array, since often
163 // times [callback] will do very heavy things (e.g. compiling the function).
164 //
165 // This means we can possibly miss a concurrently added closure function -
166 // which the caller should be ok with (or it guarantees that this cannot
167 // happen).
168 const auto& closures =
169 GrowableObjectArray::Handle(zone, object_store->closure_functions());
170 if (closures.IsNull()) {
171 return;
172 }
173
174 if (!thread->IsInStoppedMutatorsScope()) {
175 // The empty read locker scope will implicitly issue an acquire memory
176 // fence, which means any closure functions added so far will be visible and
177 // iterated further down.
178 SafepointReadRwLocker ml(thread, thread->isolate_group()->program_lock());
179 }
180
181 // We have an outer loop to ensure any new closure functions added by
182 // [callback] will be iterated as well.
183 intptr_t i = 0;
184 while (true) {
185 intptr_t current_length = closures.Length();
186 if (i == current_length) break;
187
188 current_data = closures.data();
189 if (current_data.Length() < current_length) {
190 current_length = current_data.Length();
191 }
192
193 for (; i < current_length; ++i) {
194 entry ^= current_data.At(i);
195 if (!callback(entry)) {
196 return; // Stop iteration.
197 }
198 }
199 }
200}
201
202} // namespace dart
#define DEBUG_ASSERT(cond)
Definition: assert.h:321
static intptr_t FindClosureIndex(const Function &needle)
static void AddClosureFunctionLocked(const Function &function, bool allow_implicit_closure_functions=false)
static FunctionPtr ClosureFunctionFromIndex(intptr_t idx)
static FunctionPtr LookupClosureFunctionLocked(const Function &member_function, intptr_t kernel_offset)
static void ForAllClosureFunctions(std::function< bool(const Function &)> callback)
static FunctionPtr LookupClosureFunction(const Function &member_function, intptr_t kernel_offset)
static bool IsBackgroundCompilation()
Definition: compiler.cc:298
static bool IsMatch(const Object &a, const Object &b)
static uword Hash(const Object &key)
static GrowableObjectArrayPtr New(Heap::Space space=Heap::kNew)
Definition: object.h:11144
ObjectPtr GetOrNull(const Key &key, bool *present=nullptr) const
Definition: hash_table.h:700
bool UpdateOrInsert(const Object &key, const Object &value) const
Definition: hash_table.h:713
StorageTraits::ArrayHandle & Release()
Definition: hash_table.h:195
@ kOld
Definition: heap.h:39
static ObjectPtr null()
Definition: object.h:433
ObjectPtr ptr() const
Definition: object.h:332
static Object & Handle()
Definition: object.h:407
static ObjectPtr RawCast(ObjectPtr obj)
Definition: object.h:325
static SmiPtr New(intptr_t value)
Definition: object.h:10006
static Thread * Current()
Definition: thread.h:362
#define ASSERT(E)
static bool b
struct MyStruct a[10]
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
GAsyncResult * result
Dart_NativeFunction function
Definition: fuchsia.cc:51
Definition: dart_vm.cc:33
uintptr_t uword
Definition: globals.h:501
SI auto map(std::index_sequence< I... >, Fn &&fn, const Args &... args) -> skvx::Vec< sizeof...(I), decltype(fn(args[0]...))>
Definition: SkVx.h:680