Flutter Engine
The Flutter Engine
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::kNonNullable, Heap::Space space=Heap::kOld)
Definition: object.cc:11631
int32_t FfiCallbackId() const
Definition: object.cc:8332
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:10243
StringPtr name() const
Definition: object.h:2992
static GrowableObjectArrayPtr New(Heap::Space space=Heap::kNew)
Definition: object.h:11144
@ kOld
Definition: heap.h:39
InstancePtr CopyShallowToOldSpace(Thread *thread) const
Definition: object.cc:20440
ObjectStore * object_store() const
Definition: isolate.h:510
ClassPtr toplevel_class() const
Definition: object.h:5208
static LibraryPtr FfiLibrary()
Definition: object.cc:14799
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
Definition: thread_state.h:37
static Thread * Current()
Definition: thread.h:362
IsolateGroup * isolate_group() const
Definition: thread.h:541
#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
Definition: dart_vm.cc:33
const char *const name
FfiCallbackKind
Definition: object.h:2984
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 set
Definition: switches.h:76