blob: 657817ebc2bc56cc494256384b4db5c2b70b52b1 [file] [log] [blame]
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#error "AOT runtime should not use compiler sources (including header files)"
#include <platform/globals.h>
#include "platform/assert.h"
#include "vm/compiler/backend/locations.h"
#include "vm/compiler/ffi/callback.h"
#include "vm/compiler/ffi/native_calling_convention.h"
#include "vm/compiler/ffi/native_location.h"
#include "vm/compiler/ffi/native_type.h"
#include "vm/object.h"
namespace dart {
namespace compiler {
namespace ffi {
// Values below 0 index result (result might be multiple if composite).
const intptr_t kResultIndex = -1;
// Provides the mapping from the native calling convention to the Dart calling
// convention.
// This class is set up in a query-able way so that it's underlying logic can
// be extended to support more native ABI features and calling conventions.
class BaseMarshaller : public ZoneAllocated {
intptr_t num_args() const {
return native_calling_convention_.argument_locations().length();
// Number of definitions passed to FfiCall, number of NativeParams, or number
// of definitions passed to NativeReturn in IL.
// All non-struct values have 1 definition, struct values can have either 1
// or multiple definitions. If a struct has multiple definitions, they either
// correspond to the number of native locations in the native ABI or to word-
// sized chunks.
// `arg_index` is the index of an argument.
// `def_index_in_argument` is the definition in one argument.
// `def_index_global` is the index of the definition in all arguments.
intptr_t NumDefinitions() const;
intptr_t NumDefinitions(intptr_t arg_index) const;
intptr_t NumReturnDefinitions() const;
bool ArgumentIndexIsReturn(intptr_t arg_index) const;
bool DefinitionIndexIsReturn(intptr_t def_index_global) const;
intptr_t ArgumentIndex(intptr_t def_index_global) const;
intptr_t FirstDefinitionIndex(intptr_t arg_index) const;
intptr_t DefinitionInArgument(intptr_t def_index_global,
intptr_t arg_index) const;
intptr_t DefinitionIndex(intptr_t def_index_in_arg, intptr_t arg_index) const;
// The location of the argument at `arg_index`.
const NativeLocation& Location(intptr_t arg_index) const {
if (arg_index == kResultIndex) {
return native_calling_convention_.return_location();
return *native_calling_convention_.argument_locations().At(arg_index);
// Unboxed representation on how the value is passed or received from regular
// Dart code.
// Implemented in BaseMarshaller because most Representations are the same
// in Calls and Callbacks.
Representation RepInDart(intptr_t arg_index) const {
return Location(arg_index).payload_type().AsRepresentationOverApprox(zone_);
// Representation on how the value is passed to or recieved from the FfiCall
// instruction or StaticCall, NativeParameter, and NativeReturn instructions.
virtual Representation RepInFfiCall(intptr_t def_index_global) const;
void RepsInFfiCall(intptr_t arg_index,
GrowableArray<Representation>* out) const;
// Bitcasting floats to ints, only required in SoftFP.
bool RequiresBitCast(intptr_t index) const {
return Location(index).payload_type().IsFloat() &&
// 8 or 16 bit int value to sign extend from.
const NativeType& SignExtendFrom(intptr_t arg_index) const {
return Location(arg_index).payload_type();
// The C Type (expressed in a Dart Type) of the argument at `arg_index`.
// Excluding the #0 argument which is the function pointer.
AbstractTypePtr CType(intptr_t arg_index) const;
// Requires boxing or unboxing.
bool IsPointer(intptr_t arg_index) const {
return AbstractType::Handle(zone_, CType(arg_index)).type_class_id() ==
bool IsHandle(intptr_t arg_index) const {
return AbstractType::Handle(zone_, CType(arg_index)).type_class_id() ==
bool IsStruct(intptr_t arg_index) const {
const auto& type = AbstractType::Handle(zone_, CType(arg_index));
const bool predefined = IsFfiTypeClassId(type.type_class_id());
return !predefined;
// Treated as a null constant in Dart.
bool IsVoid(intptr_t arg_index) const {
return AbstractType::Handle(zone_, CType(arg_index)).type_class_id() ==
bool ContainsHandles() const;
StringPtr function_name() const { return; }
BaseMarshaller(Zone* zone, const Function& dart_signature);
~BaseMarshaller() {}
Zone* zone_;
// Contains the function pointer as argument #0.
// The Dart signature is used for the function and argument names.
const Function& dart_signature_;
const FunctionType& c_signature_;
const NativeCallingConvention& native_calling_convention_;
class CallMarshaller : public BaseMarshaller {
CallMarshaller(Zone* zone, const Function& dart_signature)
: BaseMarshaller(zone, dart_signature) {}
virtual Representation RepInFfiCall(intptr_t def_index_global) const;
// The location of the inputs to the IL FfiCall instruction.
dart::Location LocInFfiCall(intptr_t def_index_global) const;
// Allocate a TypedData before the FfiCall and pass it in to the FfiCall so
// that it can be populated in assembly.
bool PassTypedData() const;
intptr_t TypedDataSizeInBytes() const;
// We allocate space for PointerToMemory arguments and PointerToMemory return
// locations on the stack. This is faster than allocation ExternalTypedData.
// Normal TypedData is not an option, as these might be relocated by GC
// during FFI calls.
intptr_t PassByPointerStackOffset(intptr_t arg_index) const;
// The total amount of stack space required for FFI trampolines.
intptr_t RequiredStackSpaceInBytes() const;
~CallMarshaller() {}
class CallbackMarshaller : public BaseMarshaller {
CallbackMarshaller(Zone* zone, const Function& dart_signature);
virtual Representation RepInFfiCall(intptr_t def_index_global) const;
// All parameters are saved on stack to do safe-point transition.
const NativeLocation& NativeLocationOfNativeParameter(
intptr_t def_index) const;
// All parameters are saved on stack to do safe-point transition.
dart::Location LocationOfNativeParameter(intptr_t def_index) const {
const auto& native_loc = NativeLocationOfNativeParameter(def_index);
if (native_loc.IsPointerToMemory()) {
return native_loc.AsPointerToMemory().pointer_location().AsLocation();
return native_loc.AsLocation();
~CallbackMarshaller() {}
const NativeLocations& callback_locs_;
} // namespace ffi
} // namespace compiler
} // namespace dart