[vm/ffi] Factor out FFI code shared between compiler and runtime.

Change-Id: I0b4af9cb36fd5ebc163621951486333a68baa890
Reviewed-on: https://dart-review.googlesource.com/c/93503
Commit-Queue: Samir Jindel <sjindel@google.com>
Auto-Submit: Samir Jindel <sjindel@google.com>
Reviewed-by: Daco Harkes <dacoharkes@google.com>
This commit is contained in:
Samir Jindel 2019-02-26 12:48:32 +00:00 committed by commit-bot@chromium.org
parent 2eb3ac7c02
commit f0042a3225
5 changed files with 218 additions and 126 deletions

View file

@ -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<uint8_t*>(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++.

View file

@ -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",

167
runtime/vm/compiler/ffi.cc Normal file
View file

@ -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<Representation>* ArgumentRepresentations(
const Function& signature) {
intptr_t num_arguments = signature.num_fixed_parameters() - 1;
auto result = new ZoneGrowableArray<Representation>(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<Location>* ArgumentLocations(
const ZoneGrowableArray<Representation>& arg_reps) {
intptr_t num_arguments = arg_reps.length();
auto result = new ZoneGrowableArray<Location>(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

39
runtime/vm/compiler/ffi.h Normal file
View file

@ -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 <platform/globals.h>
#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<Representation>* ArgumentRepresentations(
const Function& signature);
ZoneGrowableArray<Location>* ArgumentLocations(
const ZoneGrowableArray<Representation>& arg_reps);
} // namespace ffi
} // namespace dart
#endif // RUNTIME_VM_COMPILER_FFI_H_

View file

@ -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<Representation>* ArgumentRepresentations(
const Function& signature) {
intptr_t num_arguments = signature.num_fixed_parameters() - 1;
auto result = new ZoneGrowableArray<Representation>(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<Location>* ArgumentLocations(
const ZoneGrowableArray<Representation>& arg_representations) {
intptr_t num_arguments = arg_representations.length();
auto result = new ZoneGrowableArray<Location>(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<Location>& 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<Representation>* arg_representations =
ArgumentRepresentations(signature);
ffi::ArgumentRepresentations(signature);
ZoneGrowableArray<Location>* 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<Representation>* arg_representations =
ArgumentRepresentations(signature);
ffi::ArgumentRepresentations(signature);
ZoneGrowableArray<Location>* 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.