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/compiler/ffi/callback.h" |
6 | |
7 | #include "vm/symbols.h" |
8 | |
9 | namespace dart { |
10 | |
11 | namespace compiler { |
12 | |
13 | namespace ffi { |
14 | |
15 | FunctionPtr NativeCallbackFunction(const Function& c_signature, |
16 | const Function& dart_target, |
17 | const Instance& exceptional_return) { |
18 | Thread* const thread = Thread::Current(); |
19 | const int32_t callback_id = thread->AllocateFfiCallbackId(); |
20 | |
21 | // Create a new Function named '<target>_FfiCallback' and stick it in the |
22 | // 'dart:ffi' library. Note that these functions will never be invoked by |
23 | // Dart, so they have may have duplicate names. |
24 | Zone* const zone = thread->zone(); |
25 | const auto& name = String::Handle( |
26 | zone, Symbols::FromConcat(thread, Symbols::FfiCallback(), |
27 | String::Handle(zone, dart_target.name()))); |
28 | const Library& lib = Library::Handle(zone, Library::FfiLibrary()); |
29 | const Class& owner_class = Class::Handle(zone, lib.toplevel_class()); |
30 | const Function& function = |
31 | Function::Handle(zone, Function::New(name, FunctionLayout::kFfiTrampoline, |
32 | /*is_static=*/true, |
33 | /*is_const=*/false, |
34 | /*is_abstract=*/false, |
35 | /*is_external=*/false, |
36 | /*is_native=*/false, owner_class, |
37 | TokenPosition::kNoSource)); |
38 | function.set_is_debuggable(false); |
39 | |
40 | // Set callback-specific fields which the flow-graph builder needs to generate |
41 | // the body. |
42 | function.SetFfiCSignature(c_signature); |
43 | function.SetFfiCallbackId(callback_id); |
44 | function.SetFfiCallbackTarget(dart_target); |
45 | |
46 | // We need to load the exceptional return value as a constant in the generated |
47 | // function. Even though the FE ensures that it is a constant, it could still |
48 | // be a literal allocated in new space. We need to copy it into old space in |
49 | // that case. |
50 | // |
51 | // Exceptional return values currently cannot be pointers because we don't |
52 | // have constant pointers. |
53 | // |
54 | // TODO(36730): We'll need to extend this when we support passing/returning |
55 | // structs by value. |
56 | ASSERT(exceptional_return.IsNull() || exceptional_return.IsNumber()); |
57 | if (!exceptional_return.IsSmi() && exceptional_return.IsNew()) { |
58 | function.SetFfiCallbackExceptionalReturn(Instance::Handle( |
59 | zone, exceptional_return.CopyShallowToOldSpace(thread))); |
60 | } else { |
61 | function.SetFfiCallbackExceptionalReturn(exceptional_return); |
62 | } |
63 | |
64 | return function.raw(); |
65 | } |
66 | |
67 | } // namespace ffi |
68 | |
69 | } // namespace compiler |
70 | |
71 | } // namespace dart |
72 | |