0889552856
In preparation of having `Union` besides `Struct`, renames all mentions of `Struct` to `Compound`. Bug: https://github.com/dart-lang/sdk/issues/38491 tools/test.py ffi ffi_2 TEST=tests/ffi(_2)/(.*)by_value_(*.)_test.dart Change-Id: I47124a95d67c5afc3da9b5f5c08d0be47908f2e0 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/194423 Reviewed-by: Aske Simon Christensen <askesc@google.com>
202 lines
7.1 KiB
C++
202 lines
7.1 KiB
C++
// 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.
|
|
|
|
#ifndef RUNTIME_VM_COMPILER_FFI_MARSHALLER_H_
|
|
#define RUNTIME_VM_COMPILER_FFI_MARSHALLER_H_
|
|
|
|
#if defined(DART_PRECOMPILED_RUNTIME)
|
|
#error "AOT runtime should not use compiler sources (including header files)"
|
|
#endif // defined(DART_PRECOMPILED_RUNTIME)
|
|
|
|
#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 {
|
|
public:
|
|
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() &&
|
|
Location(index).container_type().IsInt();
|
|
}
|
|
|
|
// 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() ==
|
|
kFfiPointerCid;
|
|
}
|
|
bool IsHandle(intptr_t arg_index) const {
|
|
return AbstractType::Handle(zone_, CType(arg_index)).type_class_id() ==
|
|
kFfiHandleCid;
|
|
}
|
|
|
|
bool IsCompound(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() ==
|
|
kFfiVoidCid;
|
|
}
|
|
|
|
bool ContainsHandles() const;
|
|
|
|
StringPtr function_name() const { return dart_signature_.name(); }
|
|
|
|
protected:
|
|
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 {
|
|
public:
|
|
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;
|
|
|
|
protected:
|
|
~CallMarshaller() {}
|
|
};
|
|
|
|
class CallbackMarshaller : public BaseMarshaller {
|
|
public:
|
|
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();
|
|
}
|
|
|
|
protected:
|
|
~CallbackMarshaller() {}
|
|
|
|
const NativeLocations& callback_locs_;
|
|
};
|
|
|
|
} // namespace ffi
|
|
|
|
} // namespace compiler
|
|
|
|
} // namespace dart
|
|
|
|
#endif // RUNTIME_VM_COMPILER_FFI_MARSHALLER_H_
|