| 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 | |