diff --git a/runtime/lib/ffi.cc b/runtime/lib/ffi.cc index 807ec91d3c4..51caa29cb05 100644 --- a/runtime/lib/ffi.cc +++ b/runtime/lib/ffi.cc @@ -2,6 +2,7 @@ // 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. +#include "vm/compiler/ffi.h" #include "include/dart_api.h" #include "vm/bootstrap_natives.h" #include "vm/class_finalizer.h" @@ -212,40 +213,6 @@ static const Double& AsDouble(const Instance& instance) { return Double::Cast(instance); } -// Native data types sizes in bytes - -static const size_t kSizeUnknown = 0; - -static const intptr_t kNumElementSizes = kFfiVoidCid - kFfiPointerCid + 1; - -static const size_t element_size_table[kNumElementSizes] = { - sizeof(intptr_t), // kFfiPointerCid - kSizeUnknown, // kFfiNativeFunctionCid - 1, // kFfiInt8Cid - 2, // kFfiInt16Cid - 4, // kFfiInt32Cid - 8, // kFfiInt64Cid - 1, // kFfiUint8Cid - 2, // kFfiUint16Cid - 4, // kFfiUint32Cid - 8, // kFfiUint64Cid - sizeof(intptr_t), // kFfiIntPtrCid - 4, // kFfiFloatCid - 8, // kFfiDoubleCid - kSizeUnknown, // kFfiVoidCid -}; - -static size_t ElementSizeInBytes(intptr_t class_id) { - ASSERT(class_id != kFfiNativeFunctionCid); - ASSERT(class_id != kFfiVoidCid); - if (!RawObject::IsFfiTypeClassId(class_id)) { - // subtype of Pointer - class_id = kFfiPointerCid; - } - intptr_t index = class_id - kFfiPointerCid; - return element_size_table[index]; -} - // The remainder of this file implements the dart:ffi native methods. DEFINE_NATIVE_ENTRY(Ffi_allocate, 1, 1) { @@ -260,10 +227,10 @@ DEFINE_NATIVE_ENTRY(Ffi_allocate, 1, 1) { GET_NON_NULL_NATIVE_ARGUMENT(Integer, argCount, arguments->NativeArgAt(0)); int64_t count = argCount.AsInt64Value(); classid_t type_cid = type_arg.type_class_id(); - int64_t max_count = INTPTR_MAX / ElementSizeInBytes(type_cid); + int64_t max_count = INTPTR_MAX / ffi::ElementSizeInBytes(type_cid); CheckRange(argCount, 1, max_count, "count"); - size_t size = ElementSizeInBytes(type_cid) * count; + size_t size = ffi::ElementSizeInBytes(type_cid) * count; uint8_t* memory = reinterpret_cast(malloc(size)); if (memory == NULL) { const String& error = String::Handle(String::NewFormatted( @@ -302,7 +269,7 @@ DEFINE_NATIVE_ENTRY(Ffi_elementAt, 0, 2) { classid_t class_id = pointer_type_arg.type_class_id(); uint8_t* address = pointer.GetCMemoryAddress(); uint8_t* address_new = - address + index.AsInt64Value() * ElementSizeInBytes(class_id); + address + index.AsInt64Value() * ffi::ElementSizeInBytes(class_id); RawPointer* result = Pointer::New(pointer_type_arg, address_new); return result; } @@ -493,7 +460,7 @@ DEFINE_NATIVE_ENTRY(Ffi_sizeOf, 1, 0) { CheckSized(type_arg); classid_t type_cid = type_arg.type_class_id(); - return Smi::New(ElementSizeInBytes(type_cid)); + return Smi::New(ffi::ElementSizeInBytes(type_cid)); } // Generates assembly to trampoline from Dart into C++. diff --git a/runtime/vm/compiler/compiler_sources.gni b/runtime/vm/compiler/compiler_sources.gni index 24c985a6841..3829445f3fc 100644 --- a/runtime/vm/compiler/compiler_sources.gni +++ b/runtime/vm/compiler/compiler_sources.gni @@ -92,6 +92,8 @@ compiler_sources = [ "compiler_pass.h", "compiler_state.cc", "compiler_state.h", + "ffi.cc", + "ffi.h", "frontend/base_flow_graph_builder.cc", "frontend/base_flow_graph_builder.h", "frontend/bytecode_flow_graph_builder.cc", diff --git a/runtime/vm/compiler/ffi.cc b/runtime/vm/compiler/ffi.cc new file mode 100644 index 00000000000..e343fc7628c --- /dev/null +++ b/runtime/vm/compiler/ffi.cc @@ -0,0 +1,167 @@ +// Copyright (c) 2019, 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. + +#include "vm/compiler/ffi.h" + +namespace dart { + +namespace ffi { + +#if defined(TARGET_ARCH_X64) + +static const size_t kSizeUnknown = 0; + +static const intptr_t kNumElementSizes = kFfiVoidCid - kFfiPointerCid + 1; + +static const size_t element_size_table[kNumElementSizes] = { + sizeof(intptr_t), // kFfiPointerCid + kSizeUnknown, // kFfiNativeFunctionCid + 1, // kFfiInt8Cid + 2, // kFfiInt16Cid + 4, // kFfiInt32Cid + 8, // kFfiInt64Cid + 1, // kFfiUint8Cid + 2, // kFfiUint16Cid + 4, // kFfiUint32Cid + 8, // kFfiUint64Cid + sizeof(intptr_t), // kFfiIntPtrCid + 4, // kFfiFloatCid + 8, // kFfiDoubleCid + kSizeUnknown, // kFfiVoidCid +}; + +Representation WordRep() { + return compiler::target::kWordSize > 4 ? kUnboxedInt64 : kUnboxedInt32; +} + +size_t ElementSizeInBytes(intptr_t class_id) { + ASSERT(class_id != kFfiNativeFunctionCid); + ASSERT(class_id != kFfiVoidCid); + if (!RawObject::IsFfiTypeClassId(class_id)) { + // subtype of Pointer + class_id = kFfiPointerCid; + } + intptr_t index = class_id - kFfiPointerCid; + return element_size_table[index]; +} + +bool ElementIsSigned(intptr_t class_id) { + switch (class_id) { + case kFfiFloatCid: + case kFfiDoubleCid: + case kFfiInt8Cid: + case kFfiInt16Cid: + case kFfiInt32Cid: + case kFfiInt64Cid: + case kFfiIntPtrCid: + return true; + case kFfiUint8Cid: + case kFfiUint16Cid: + case kFfiUint32Cid: + case kFfiUint64Cid: + case kFfiPointerCid: + default: // Subtypes of Pointer. + return false; + } +} + +Representation TypeRepresentation(const AbstractType& result_type) { + switch (result_type.type_class_id()) { + case kFfiFloatCid: + case kFfiDoubleCid: + return kUnboxedDouble; + case kFfiInt8Cid: + case kFfiInt16Cid: + case kFfiInt32Cid: + case kFfiUint8Cid: + case kFfiUint16Cid: + case kFfiUint32Cid: + return kUnboxedInt32; + case kFfiInt64Cid: + case kFfiUint64Cid: + return kUnboxedInt64; + case kFfiIntPtrCid: + case kFfiPointerCid: + default: // Subtypes of Pointer. + return WordRep(); + } +} + +// Converts a Ffi [signature] to a list of Representations. +// Note that this ignores first argument (receiver) which is dynamic. +ZoneGrowableArray* ArgumentRepresentations( + const Function& signature) { + intptr_t num_arguments = signature.num_fixed_parameters() - 1; + auto result = new ZoneGrowableArray(num_arguments); + for (intptr_t i = 0; i < num_arguments; i++) { + AbstractType& arg_type = + AbstractType::Handle(signature.ParameterTypeAt(i + 1)); + result->Add(TypeRepresentation(arg_type)); + } + return result; +} + +// Takes a list of argument representations, and converts it to a list of +// argument locations based on calling convention. +ZoneGrowableArray* ArgumentLocations( + const ZoneGrowableArray& arg_reps) { + intptr_t num_arguments = arg_reps.length(); + auto result = new ZoneGrowableArray(num_arguments); + result->FillWith(Location(), 0, num_arguments); + Location* data = result->data(); + + // Loop through all arguments and assign a register or a stack location. + intptr_t regs_used = 0; + intptr_t xmm_regs_used = 0; + intptr_t nth_stack_argument = 0; + bool on_stack; + for (intptr_t i = 0; i < num_arguments; i++) { + on_stack = true; + switch (arg_reps.At(i)) { + case kUnboxedInt32: + case kUnboxedInt64: + if (regs_used < CallingConventions::kNumArgRegs) { + data[i] = Location::RegisterLocation( + CallingConventions::ArgumentRegisters[regs_used]); + regs_used++; + if (CallingConventions::kArgumentIntRegXorXmmReg) { + xmm_regs_used++; + } + on_stack = false; + } + break; + case kUnboxedDouble: + if (xmm_regs_used < CallingConventions::kNumXmmArgRegs) { + data[i] = Location::FpuRegisterLocation( + CallingConventions::XmmArgumentRegisters[xmm_regs_used]); + xmm_regs_used++; + if (CallingConventions::kArgumentIntRegXorXmmReg) { + regs_used++; + } + on_stack = false; + } + break; + default: + UNREACHABLE(); + } + if (on_stack) { + // SAMIR_TODO: Is this correct? + data[i] = Location::StackSlot(nth_stack_argument, RSP); + nth_stack_argument++; + } + } + return result; +} + +#else + +size_t ElementSizeInBytes(intptr_t class_id) { + UNREACHABLE(); +} + +#endif + +} // namespace ffi + +} // namespace dart diff --git a/runtime/vm/compiler/ffi.h b/runtime/vm/compiler/ffi.h new file mode 100644 index 00000000000..b66818b352c --- /dev/null +++ b/runtime/vm/compiler/ffi.h @@ -0,0 +1,39 @@ +// Copyright (c) 2019, 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_H_ +#define RUNTIME_VM_COMPILER_FFI_H_ + +#include + +#include "../class_id.h" +#include "../object.h" +#include "../raw_object.h" +#include "backend/locations.h" + +namespace dart { + +namespace ffi { + +// Native data types sizes in bytes + +size_t ElementSizeInBytes(intptr_t class_id); + +bool ElementIsSigned(intptr_t class_id); + +Representation TypeRepresentation(const AbstractType& result_type); + +Representation WordRep(); + +ZoneGrowableArray* ArgumentRepresentations( + const Function& signature); + +ZoneGrowableArray* ArgumentLocations( + const ZoneGrowableArray& arg_reps); + +} // namespace ffi + +} // namespace dart + +#endif // RUNTIME_VM_COMPILER_FFI_H_ diff --git a/runtime/vm/ffi_trampoline_stubs_x64.cc b/runtime/vm/ffi_trampoline_stubs_x64.cc index 001c68d229e..560194cbe05 100644 --- a/runtime/vm/ffi_trampoline_stubs_x64.cc +++ b/runtime/vm/ffi_trampoline_stubs_x64.cc @@ -14,6 +14,7 @@ #include "vm/compiler/assembler/assembler.h" #include "vm/compiler/assembler/disassembler.h" #include "vm/compiler/backend/flow_graph_compiler.h" +#include "vm/compiler/ffi.h" #include "vm/compiler/jit/compiler.h" #include "vm/constants_x64.h" #include "vm/dart_entry.h" @@ -30,90 +31,6 @@ namespace dart { -static Representation TypeRepresentation(const AbstractType& result_type) { - switch (result_type.type_class_id()) { - case kFfiFloatCid: - case kFfiDoubleCid: - return kUnboxedDouble; - case kFfiInt8Cid: - case kFfiInt16Cid: - case kFfiInt32Cid: - case kFfiInt64Cid: - case kFfiUint8Cid: - case kFfiUint16Cid: - case kFfiUint32Cid: - case kFfiUint64Cid: - case kFfiIntPtrCid: - case kFfiPointerCid: - default: // Subtypes of Pointer. - return kUnboxedInt64; - } -} - -// Converts a Ffi [signature] to a list of Representations. -// Note that this ignores first argument (receiver) which is dynamic. -static ZoneGrowableArray* ArgumentRepresentations( - const Function& signature) { - intptr_t num_arguments = signature.num_fixed_parameters() - 1; - auto result = new ZoneGrowableArray(num_arguments); - for (intptr_t i = 0; i < num_arguments; i++) { - AbstractType& arg_type = - AbstractType::Handle(signature.ParameterTypeAt(i + 1)); - result->Add(TypeRepresentation(arg_type)); - } - return result; -} - -// Takes a list of argument representations, and converts it to a list of -// argument locations based on calling convention. -static ZoneGrowableArray* ArgumentLocations( - const ZoneGrowableArray& arg_representations) { - intptr_t num_arguments = arg_representations.length(); - auto result = new ZoneGrowableArray(num_arguments); - result->FillWith(Location(), 0, num_arguments); - Location* data = result->data(); - - // Loop through all arguments and assign a register or a stack location. - intptr_t int_regs_used = 0; - intptr_t xmm_regs_used = 0; - intptr_t nth_stack_argument = 0; - bool on_stack; - for (intptr_t i = 0; i < num_arguments; i++) { - on_stack = true; - switch (arg_representations.At(i)) { - case kUnboxedInt64: - if (int_regs_used < CallingConventions::kNumArgRegs) { - data[i] = Location::RegisterLocation( - CallingConventions::ArgumentRegisters[int_regs_used]); - int_regs_used++; - if (CallingConventions::kArgumentIntRegXorXmmReg) { - xmm_regs_used++; - } - on_stack = false; - } - break; - case kUnboxedDouble: - if (xmm_regs_used < CallingConventions::kNumXmmArgRegs) { - data[i] = Location::FpuRegisterLocation( - CallingConventions::XmmArgumentRegisters[xmm_regs_used]); - xmm_regs_used++; - if (CallingConventions::kArgumentIntRegXorXmmReg) { - int_regs_used++; - } - on_stack = false; - } - break; - default: - UNREACHABLE(); - } - if (on_stack) { - data[i] = Location::StackSlot(nth_stack_argument, RSP); - nth_stack_argument++; - } - } - return result; -} - static intptr_t NumStackArguments( const ZoneGrowableArray& locations) { intptr_t num_arguments = locations.length(); @@ -445,9 +362,9 @@ static void GenerateUnmarshalResult(Assembler* assembler, // TODO(dacoharkes): Test truncation on non 64 bits ints and floats. void GenerateFfiTrampoline(Assembler* assembler, const Function& signature) { ZoneGrowableArray* arg_representations = - ArgumentRepresentations(signature); + ffi::ArgumentRepresentations(signature); ZoneGrowableArray* arg_locations = - ArgumentLocations(*arg_representations); + ffi::ArgumentLocations(*arg_representations); intptr_t num_dart_arguments = signature.num_fixed_parameters(); intptr_t num_arguments = num_dart_arguments - 1; // ignore closure @@ -536,9 +453,9 @@ void GenerateFfiInverseTrampoline(Assembler* assembler, const Function& signature, void* dart_entry_point) { ZoneGrowableArray* arg_representations = - ArgumentRepresentations(signature); + ffi::ArgumentRepresentations(signature); ZoneGrowableArray* arg_locations = - ArgumentLocations(*arg_representations); + ffi::ArgumentLocations(*arg_representations); intptr_t num_dart_arguments = signature.num_fixed_parameters(); intptr_t num_arguments = num_dart_arguments - 1; // Ignore closure.