Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
callback.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
9#include "vm/object_store.h"
10#include "vm/symbols.h"
11
12namespace dart {
13
14namespace compiler {
15
16namespace ffi {
17
19 Zone* zone,
20 const Function& dart_target,
21 FfiCallbackKind kind) {
22 switch (kind) {
24 return Symbols::FfiAsyncCallback();
26 return Symbols::FfiIsolateLocalCallback();
28 return String::Handle(
29 zone, Symbols::FromConcat(thread, Symbols::FfiCallback(),
30 String::Handle(zone, dart_target.name())));
31 default:
33 }
34}
35
36FunctionPtr NativeCallbackFunction(const FunctionType& c_signature,
37 const Function& dart_target,
38 const Instance& exceptional_return,
39 FfiCallbackKind kind) {
40 Thread* const thread = Thread::Current();
41 Zone* const zone = thread->zone();
43 ASSERT(c_signature.IsCanonical());
44 ASSERT(exceptional_return.IsSmi() || exceptional_return.IsCanonical());
45
46 // Create a new Function named '<target>_FfiCallback' and stick it in the
47 // 'dart:ffi' library. Note that these functions will never be invoked by
48 // Dart, so they may have duplicate names.
49 const auto& name =
50 NativeCallbackFunctionName(thread, zone, dart_target, kind);
51 const Library& lib = Library::Handle(zone, Library::FfiLibrary());
52 const Class& owner_class = Class::Handle(zone, lib.toplevel_class());
53 auto& signature = FunctionType::Handle(zone, FunctionType::New());
54 function =
55 Function::New(signature, name, UntaggedFunction::kFfiTrampoline,
56 /*is_static=*/true,
57 /*is_const=*/false,
58 /*is_abstract=*/false,
59 /*is_external=*/false,
60 /*is_native=*/false, owner_class, TokenPosition::kNoSource);
61 function.set_is_debuggable(false);
62
63 // Set callback-specific fields which the flow-graph builder needs to generate
64 // the body.
65 function.SetFfiCSignature(c_signature);
66 function.SetFfiCallbackTarget(dart_target);
67 function.SetFfiCallbackKind(kind);
68
69 // We need to load the exceptional return value as a constant in the generated
70 // function. Even though the FE ensures that it is a constant, it could still
71 // be a literal allocated in new space. We need to copy it into old space in
72 // that case.
73 //
74 // Exceptional return values currently cannot be pointers because we don't
75 // have constant pointers.
76 ASSERT(exceptional_return.IsNull() || exceptional_return.IsNumber() ||
77 exceptional_return.IsBool());
78 if (!exceptional_return.IsSmi() && exceptional_return.IsNew()) {
79 function.SetFfiCallbackExceptionalReturn(Instance::Handle(
80 zone, exceptional_return.CopyShallowToOldSpace(thread)));
81 } else {
82 function.SetFfiCallbackExceptionalReturn(exceptional_return);
83 }
84
85 // The dart type of the FfiCallback has no arguments or type arguments and
86 // has a result type of dynamic, as the callback is never invoked via Dart,
87 // only via native calls that do not use this information. Having no Dart
88 // arguments ensures the scope builder does not add inappropriate parameter
89 // variables.
90 signature.set_result_type(Object::dynamic_type());
91 // Finalize (and thus canonicalize) the signature.
92 signature ^= ClassFinalizer::FinalizeType(signature);
93 function.SetSignature(signature);
94
95 {
96 // Ensure only one thread updates the cache of deduped ffi trampoline
97 // functions.
98 auto isolate_group = thread->isolate_group();
99 SafepointWriteRwLocker ml(thread, isolate_group->program_lock());
100
101 auto object_store = isolate_group->object_store();
102 if (object_store->ffi_callback_functions() == Array::null()) {
104 HashTables::New<FfiCallbackFunctionSet>(/*initial_capacity=*/4));
105 object_store->set_ffi_callback_functions(set.Release());
106 }
107 FfiCallbackFunctionSet set(object_store->ffi_callback_functions());
108
109 const intptr_t entry_count_before = set.NumOccupied();
110 function ^= set.InsertOrGet(function);
111 const intptr_t entry_count_after = set.NumOccupied();
112
113 object_store->set_ffi_callback_functions(set.Release());
114
115 if (entry_count_before != entry_count_after) {
116 function.AssignFfiCallbackId(entry_count_before);
117 } else {
118 ASSERT(function.FfiCallbackId() != -1);
119 }
120 }
121
122 return function.ptr();
123}
124
125static void EnsureFfiCallbackMetadata(Thread* thread, intptr_t callback_id) {
126 static constexpr intptr_t kInitialCallbackIdsReserved = 16;
127
128 auto object_store = thread->isolate_group()->object_store();
129 auto zone = thread->zone();
130
131 auto& code_array =
132 GrowableObjectArray::Handle(zone, object_store->ffi_callback_code());
133 if (code_array.IsNull()) {
134 code_array =
135 GrowableObjectArray::New(kInitialCallbackIdsReserved, Heap::kOld);
136 object_store->set_ffi_callback_code(code_array);
137 }
138 if (code_array.Length() <= callback_id) {
139 // Ensure we've enough space in the arrays.
140 while (!(callback_id < code_array.Length())) {
141 code_array.Add(Code::null_object());
142 }
143 }
144
145 ASSERT(callback_id < code_array.Length());
146}
147
149 const Function& ffi_trampoline,
150 const Code& code) {
151 auto zone = thread->zone();
152
153 const intptr_t callback_id = ffi_trampoline.FfiCallbackId();
154 EnsureFfiCallbackMetadata(thread, callback_id);
155
156 auto object_store = thread->isolate_group()->object_store();
157 const auto& code_array =
158 GrowableObjectArray::Handle(zone, object_store->ffi_callback_code());
159 code_array.SetAt(callback_id, code);
160}
161
162} // namespace ffi
163
164} // namespace compiler
165
166} // namespace dart
#define UNREACHABLE()
Definition assert.h:248
static AbstractTypePtr FinalizeType(const AbstractType &type, FinalizationKind finalization=kCanonicalize)
static FunctionTypePtr New(intptr_t num_parent_type_arguments=0, Nullability nullability=Nullability::kLegacy, Heap::Space space=Heap::kOld)
Definition object.cc:11682
int32_t FfiCallbackId() const
Definition object.cc:8390
static FunctionPtr New(const FunctionType &signature, const String &name, UntaggedFunction::Kind kind, bool is_static, bool is_const, bool is_abstract, bool is_external, bool is_native, const Object &owner, TokenPosition token_pos, Heap::Space space=Heap::kOld)
Definition object.cc:10301
StringPtr name() const
Definition object.h:2972
static GrowableObjectArrayPtr New(Heap::Space space=Heap::kNew)
Definition object.h:11118
@ kOld
Definition heap.h:39
InstancePtr CopyShallowToOldSpace(Thread *thread) const
Definition object.cc:20481
ObjectStore * object_store() const
Definition isolate.h:505
ClassPtr toplevel_class() const
Definition object.h:5179
static LibraryPtr FfiLibrary()
Definition object.cc:14846
static ObjectPtr null()
Definition object.h:433
bool IsCanonical() const
Definition object.h:335
bool IsNew() const
Definition object.h:390
bool IsNull() const
Definition object.h:363
static Object & Handle()
Definition object.h:407
static StringPtr FromConcat(Thread *thread, const String &str1, const String &str2)
Definition symbols.cc:235
Zone * zone() const
static Thread * Current()
Definition thread.h:361
IsolateGroup * isolate_group() const
Definition thread.h:540
#define ASSERT(E)
Dart_NativeFunction function
Definition fuchsia.cc:51
const String & NativeCallbackFunctionName(Thread *thread, Zone *zone, const Function &dart_target, FfiCallbackKind kind)
Definition callback.cc:18
void SetFfiCallbackCode(Thread *thread, const Function &ffi_trampoline, const Code &code)
Definition callback.cc:148
static void EnsureFfiCallbackMetadata(Thread *thread, intptr_t callback_id)
Definition callback.cc:125
FunctionPtr NativeCallbackFunction(const FunctionType &c_signature, const Function &dart_target, const Instance &exceptional_return, FfiCallbackKind kind)
Definition callback.cc:36
const char *const name
FfiCallbackKind
Definition object.h:2964