mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 06:20:13 +00:00
[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:
parent
2eb3ac7c02
commit
f0042a3225
5 changed files with 218 additions and 126 deletions
|
@ -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++.
|
||||
|
|
|
@ -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
167
runtime/vm/compiler/ffi.cc
Normal 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
39
runtime/vm/compiler/ffi.h
Normal 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_
|
|
@ -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.
|
||||
|
|
Loading…
Reference in a new issue