Skip to content

Commit

Permalink
[vm/ffi] Refactor IL construction to compound
Browse files Browse the repository at this point in the history
In preparation of having `Union` besides `Struct`, renames all mentions
of `Struct` to `Compound`.

Bug: #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>
  • Loading branch information
dcharkes authored and commit-bot@chromium.org committed Apr 13, 2021
1 parent bde9578 commit 0889552
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 61 deletions.
2 changes: 1 addition & 1 deletion runtime/vm/compiler/ffi/marshaller.cc
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,7 @@ Location CallMarshaller::LocInFfiCall(intptr_t def_index_global) const {
}

bool CallMarshaller::PassTypedData() const {
return IsStruct(compiler::ffi::kResultIndex);
return IsCompound(compiler::ffi::kResultIndex);
}

intptr_t CallMarshaller::TypedDataSizeInBytes() const {
Expand Down
2 changes: 1 addition & 1 deletion runtime/vm/compiler/ffi/marshaller.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ class BaseMarshaller : public ZoneAllocated {
kFfiHandleCid;
}

bool IsStruct(intptr_t arg_index) const {
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;
Expand Down
81 changes: 41 additions & 40 deletions runtime/vm/compiler/frontend/kernel_to_il.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3776,10 +3776,11 @@ Fragment FlowGraphBuilder::BitCast(Representation from, Representation to) {
return Fragment(instr);
}

Fragment FlowGraphBuilder::WrapTypedDataBaseInStruct(
const AbstractType& struct_type) {
const auto& struct_sub_class = Class::ZoneHandle(Z, struct_type.type_class());
struct_sub_class.EnsureIsFinalized(thread_);
Fragment FlowGraphBuilder::WrapTypedDataBaseInCompound(
const AbstractType& compound_type) {
const auto& compound_sub_class =
Class::ZoneHandle(Z, compound_type.type_class());
compound_sub_class.EnsureIsFinalized(thread_);
const auto& lib_ffi = Library::Handle(Z, Library::FfiLibrary());
const auto& compound_class =
Class::Handle(Z, lib_ffi.LookupClassAllowPrivate(Symbols::Compound()));
Expand All @@ -3790,16 +3791,16 @@ Fragment FlowGraphBuilder::WrapTypedDataBaseInStruct(

Fragment body;
LocalVariable* typed_data = MakeTemporary("typed_data_base");
body += AllocateObject(TokenPosition::kNoSource, struct_sub_class, 0);
body += LoadLocal(MakeTemporary("struct")); // Duplicate Struct.
body += AllocateObject(TokenPosition::kNoSource, compound_sub_class, 0);
body += LoadLocal(MakeTemporary("compound")); // Duplicate Struct or Union.
body += LoadLocal(typed_data);
body += StoreInstanceField(compound_typed_data_base,
StoreInstanceFieldInstr::Kind::kInitializing);
body += DropTempsPreserveTop(1); // Drop TypedData.
return body;
}

Fragment FlowGraphBuilder::LoadTypedDataBaseFromStruct() {
Fragment FlowGraphBuilder::LoadTypedDataBaseFromCompound() {
const auto& lib_ffi = Library::Handle(Z, Library::FfiLibrary());
const auto& compound_class =
Class::Handle(Z, lib_ffi.LookupClassAllowPrivate(Symbols::Compound()));
Expand All @@ -3813,15 +3814,15 @@ Fragment FlowGraphBuilder::LoadTypedDataBaseFromStruct() {
return body;
}

Fragment FlowGraphBuilder::CopyFromStructToStack(
Fragment FlowGraphBuilder::CopyFromCompoundToStack(
LocalVariable* variable,
const GrowableArray<Representation>& representations) {
Fragment body;
const intptr_t num_defs = representations.length();
int offset_in_bytes = 0;
for (intptr_t i = 0; i < num_defs; i++) {
body += LoadLocal(variable);
body += LoadTypedDataBaseFromStruct();
body += LoadTypedDataBaseFromCompound();
body += LoadUntagged(compiler::target::Pointer::data_field_offset());
body += IntConstant(offset_in_bytes);
const Representation representation = representations[i];
Expand Down Expand Up @@ -3959,7 +3960,7 @@ Fragment FlowGraphBuilder::CopyFromUnboxedAddressToTypedDataBase(
return body;
}

Fragment FlowGraphBuilder::FfiCallConvertStructArgumentToNative(
Fragment FlowGraphBuilder::FfiCallConvertCompoundArgumentToNative(
LocalVariable* variable,
const compiler::ffi::BaseMarshaller& marshaller,
intptr_t arg_index) {
Expand All @@ -3970,29 +3971,29 @@ Fragment FlowGraphBuilder::FfiCallConvertStructArgumentToNative(
// separate definitions into the FFI call.
GrowableArray<Representation> representations;
marshaller.RepsInFfiCall(arg_index, &representations);
body += CopyFromStructToStack(variable, representations);
body += CopyFromCompoundToStack(variable, representations);
} else {
ASSERT(native_loc.IsPointerToMemory());
// Only load the typed data, do copying in the FFI call machine code.
body += LoadLocal(variable); // User-defined struct.
body += LoadTypedDataBaseFromStruct();
body += LoadTypedDataBaseFromCompound();
}
return body;
}

Fragment FlowGraphBuilder::FfiCallConvertStructReturnToDart(
Fragment FlowGraphBuilder::FfiCallConvertCompoundReturnToDart(
const compiler::ffi::BaseMarshaller& marshaller,
intptr_t arg_index) {
Fragment body;
// The typed data is allocated before the FFI call, and is populated in
// machine code. So, here, it only has to be wrapped in the struct class.
const auto& struct_type =
const auto& compound_type =
AbstractType::Handle(Z, marshaller.CType(arg_index));
body += WrapTypedDataBaseInStruct(struct_type);
body += WrapTypedDataBaseInCompound(compound_type);
return body;
}

Fragment FlowGraphBuilder::FfiCallbackConvertStructArgumentToDart(
Fragment FlowGraphBuilder::FfiCallbackConvertCompoundArgumentToDart(
const compiler::ffi::BaseMarshaller& marshaller,
intptr_t arg_index,
ZoneGrowableArray<LocalVariable*>* definitions) {
Expand All @@ -4012,39 +4013,39 @@ Fragment FlowGraphBuilder::FfiCallbackConvertStructArgumentToDart(
} else {
ASSERT(marshaller.Location(arg_index).IsPointerToMemory());
// Allocate a TypedData and copy contents pointed to by an address into it.
LocalVariable* address_of_struct = MakeTemporary("address_of_struct");
LocalVariable* address_of_compound = MakeTemporary("address_of_compound");
body += IntConstant(length_in_bytes);
body +=
AllocateTypedData(TokenPosition::kNoSource, kTypedDataUint8ArrayCid);
LocalVariable* typed_data_base = MakeTemporary("typed_data_base");
body += LoadLocal(address_of_struct);
body += LoadLocal(address_of_compound);
body += LoadLocal(typed_data_base);
body += CopyFromUnboxedAddressToTypedDataBase(length_in_bytes);
body += DropTempsPreserveTop(1); // address_of_struct.
body += DropTempsPreserveTop(1); // address_of_compound.
}
// Wrap typed data in struct class.
const auto& struct_type =
// Wrap typed data in compound class.
const auto& compound_type =
AbstractType::Handle(Z, marshaller.CType(arg_index));
body += WrapTypedDataBaseInStruct(struct_type);
body += WrapTypedDataBaseInCompound(compound_type);
return body;
}

Fragment FlowGraphBuilder::FfiCallbackConvertStructReturnToNative(
Fragment FlowGraphBuilder::FfiCallbackConvertCompoundReturnToNative(
const compiler::ffi::CallbackMarshaller& marshaller,
intptr_t arg_index) {
Fragment body;
const auto& native_loc = marshaller.Location(arg_index);
if (native_loc.IsMultiple()) {
// We pass in typed data to native return instruction, and do the copying
// in machine code.
body += LoadTypedDataBaseFromStruct();
body += LoadTypedDataBaseFromCompound();
} else {
ASSERT(native_loc.IsPointerToMemory());
// We copy the data into the right location in IL.
const intptr_t length_in_bytes =
marshaller.Location(arg_index).payload_type().SizeInBytes();

body += LoadTypedDataBaseFromStruct();
body += LoadTypedDataBaseFromCompound();
LocalVariable* typed_data_base = MakeTemporary("typed_data_base");

auto* pointer_to_return =
Expand All @@ -4065,7 +4066,7 @@ Fragment FlowGraphBuilder::FfiCallbackConvertStructReturnToNative(
Fragment FlowGraphBuilder::FfiConvertPrimitiveToDart(
const compiler::ffi::BaseMarshaller& marshaller,
intptr_t arg_index) {
ASSERT(!marshaller.IsStruct(arg_index));
ASSERT(!marshaller.IsCompound(arg_index));

Fragment body;
if (marshaller.IsPointer(arg_index)) {
Expand Down Expand Up @@ -4093,7 +4094,7 @@ Fragment FlowGraphBuilder::FfiConvertPrimitiveToNative(
const compiler::ffi::BaseMarshaller& marshaller,
intptr_t arg_index,
LocalVariable* api_local_scope) {
ASSERT(!marshaller.IsStruct(arg_index));
ASSERT(!marshaller.IsCompound(arg_index));

Fragment body;
if (marshaller.IsPointer(arg_index)) {
Expand Down Expand Up @@ -4195,8 +4196,8 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfFfiNative(const Function& function) {

// Unbox and push the arguments.
for (intptr_t i = 0; i < marshaller.num_args(); i++) {
if (marshaller.IsStruct(i)) {
body += FfiCallConvertStructArgumentToNative(
if (marshaller.IsCompound(i)) {
body += FfiCallConvertCompoundArgumentToNative(
parsed_function_->ParameterVariable(kFirstArgumentParameterOffset +
i),
marshaller, i);
Expand Down Expand Up @@ -4246,9 +4247,9 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfFfiNative(const Function& function) {
body += Drop();
}

if (marshaller.IsStruct(compiler::ffi::kResultIndex)) {
body += FfiCallConvertStructReturnToDart(marshaller,
compiler::ffi::kResultIndex);
if (marshaller.IsCompound(compiler::ffi::kResultIndex)) {
body += FfiCallConvertCompoundReturnToDart(marshaller,
compiler::ffi::kResultIndex);
} else {
body += FfiConvertPrimitiveToDart(marshaller, compiler::ffi::kResultIndex);
}
Expand Down Expand Up @@ -4322,8 +4323,8 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfFfiCallback(const Function& function) {
defs->Add(def);
}

if (marshaller.IsStruct(i)) {
body += FfiCallbackConvertStructArgumentToDart(marshaller, i, defs);
if (marshaller.IsCompound(i)) {
body += FfiCallbackConvertCompoundArgumentToDart(marshaller, i, defs);
} else {
body += FfiConvertPrimitiveToDart(marshaller, i);
}
Expand All @@ -4346,9 +4347,9 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfFfiCallback(const Function& function) {
String::ZoneHandle(Z, marshaller.function_name()));
}

if (marshaller.IsStruct(compiler::ffi::kResultIndex)) {
body += FfiCallbackConvertStructReturnToNative(marshaller,
compiler::ffi::kResultIndex);
if (marshaller.IsCompound(compiler::ffi::kResultIndex)) {
body += FfiCallbackConvertCompoundReturnToNative(
marshaller, compiler::ffi::kResultIndex);
} else {
body += FfiConvertPrimitiveToNative(marshaller, compiler::ffi::kResultIndex,
/*api_local_scope=*/nullptr);
Expand Down Expand Up @@ -4379,7 +4380,7 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfFfiCallback(const Function& function) {
FfiConvertPrimitiveToNative(marshaller, compiler::ffi::kResultIndex,
/*api_local_scope=*/nullptr);

} else if (marshaller.IsStruct(compiler::ffi::kResultIndex)) {
} else if (marshaller.IsCompound(compiler::ffi::kResultIndex)) {
ASSERT(function.FfiCallbackExceptionalReturn() == Object::null());
// Manufacture empty result.
const intptr_t size =
Expand All @@ -4390,9 +4391,9 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfFfiCallback(const Function& function) {
catch_body += IntConstant(size);
catch_body +=
AllocateTypedData(TokenPosition::kNoSource, kTypedDataUint8ArrayCid);
catch_body += WrapTypedDataBaseInStruct(
catch_body += WrapTypedDataBaseInCompound(
AbstractType::Handle(Z, marshaller.CType(compiler::ffi::kResultIndex)));
catch_body += FfiCallbackConvertStructReturnToNative(
catch_body += FfiCallbackConvertCompoundReturnToNative(
marshaller, compiler::ffi::kResultIndex);

} else {
Expand Down
40 changes: 21 additions & 19 deletions runtime/vm/compiler/frontend/kernel_to_il.h
Original file line number Diff line number Diff line change
Expand Up @@ -293,44 +293,46 @@ class FlowGraphBuilder : public BaseFlowGraphBuilder {
intptr_t arg_index);

// We pass in `variable` instead of on top of the stack so that we can have
// multiple consecutive calls that keep only struct parts on the stack with
// no struct parts in between.
Fragment FfiCallConvertStructArgumentToNative(
// multiple consecutive calls that keep only compound parts on the stack with
// no compound parts in between.
Fragment FfiCallConvertCompoundArgumentToNative(
LocalVariable* variable,
const compiler::ffi::BaseMarshaller& marshaller,
intptr_t arg_index);

Fragment FfiCallConvertStructReturnToDart(
Fragment FfiCallConvertCompoundReturnToDart(
const compiler::ffi::BaseMarshaller& marshaller,
intptr_t arg_index);

// We pass in multiple `definitions`, which are also expected to be the top
// of the stack. This eases storing each definition in the resulting struct.
Fragment FfiCallbackConvertStructArgumentToDart(
// of the stack. This eases storing each definition in the resulting struct
// or union.
Fragment FfiCallbackConvertCompoundArgumentToDart(
const compiler::ffi::BaseMarshaller& marshaller,
intptr_t arg_index,
ZoneGrowableArray<LocalVariable*>* definitions);

Fragment FfiCallbackConvertStructReturnToNative(
Fragment FfiCallbackConvertCompoundReturnToNative(
const compiler::ffi::CallbackMarshaller& marshaller,
intptr_t arg_index);

// Wraps a TypedDataBase from the stack and wraps it in a subclass of Struct.
Fragment WrapTypedDataBaseInStruct(const AbstractType& struct_type);
// Wraps a TypedDataBase from the stack and wraps it in a subclass of
// _Compound.
Fragment WrapTypedDataBaseInCompound(const AbstractType& compound_type);

// Loads the _typedDataBase field from a subclass of Struct.
Fragment LoadTypedDataBaseFromStruct();
// Loads the _typedDataBase field from a subclass of _Compound.
Fragment LoadTypedDataBaseFromCompound();

// Breaks up a subclass of Struct in multiple definitions and puts them on
// Breaks up a subclass of _Compound in multiple definitions and puts them on
// the stack.
//
// Takes in the Struct as a local `variable` so that can be anywhere on the
// stack and this function can be called multiple times to leave only the
// results of this function on the stack without any Structs in between.
// Takes in the _Compound as a local `variable` so that can be anywhere on
// the stack and this function can be called multiple times to leave only the
// results of this function on the stack without any _Compounds in between.
//
// The struct contents are heterogeneous, so pass in `representations` to
// know what representation to load.
Fragment CopyFromStructToStack(
// The compound contents are heterogeneous, so pass in
// `representations` to know what representation to load.
Fragment CopyFromCompoundToStack(
LocalVariable* variable,
const GrowableArray<Representation>& representations);

Expand All @@ -340,7 +342,7 @@ class FlowGraphBuilder : public BaseFlowGraphBuilder {
//
// Leaves TypedData on stack.
//
// The struct contents are heterogeneous, so pass in `representations` to
// The compound contents are heterogeneous, so pass in `representations` to
// know what representation to load.
Fragment PopFromStackToTypedDataBase(
ZoneGrowableArray<LocalVariable*>* definitions,
Expand Down

0 comments on commit 0889552

Please sign in to comment.