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
9namespace dart {
10
11namespace compiler {
12
13namespace ffi {
14
15FunctionPtr 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