[vm] Support serialization of FFI callbacks in IL serialization
TEST=tests/ffi/function_callbacks_test.dart TEST=Manual run of vm-kernel-precomp-linux-debug-x64-try with --test_il_serialization enabled. Issue: https://github.com/dart-lang/sdk/issues/43299 Change-Id: Ia57021d9091e8a80de3645cb4723ebdbb5a3d33d Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/256371 Commit-Queue: Alexander Markov <alexmarkov@google.com> Reviewed-by: Daco Harkes <dacoharkes@google.com>
This commit is contained in:
committed by
Commit Bot
parent
2da3806823
commit
a7f7c0c5ac
+2
-1
@@ -114,7 +114,8 @@ DEFINE_NATIVE_ENTRY(Ffi_nativeCallbackFunction, 1, 2) {
|
||||
// _pointerFromFunction and will not leak out into user code.
|
||||
arguments->SetReturn(
|
||||
Function::Handle(zone, compiler::ffi::NativeCallbackFunction(
|
||||
native_signature, func, exceptional_return)));
|
||||
native_signature, func, exceptional_return,
|
||||
/*register_function=*/false)));
|
||||
|
||||
// Because we have already set the return value.
|
||||
return Object::sentinel().ptr();
|
||||
|
||||
@@ -1387,7 +1387,7 @@ class FfiTrampolineDataSerializationCluster : public SerializationCluster {
|
||||
WriteFromTo(data);
|
||||
|
||||
if (s->kind() == Snapshot::kFullAOT) {
|
||||
s->WriteUnsigned(data->untag()->callback_id_);
|
||||
s->Write<int32_t>(data->untag()->callback_id_);
|
||||
} else {
|
||||
// FFI callbacks can only be written to AOT snapshots.
|
||||
ASSERT(data->untag()->callback_target() == Object::null());
|
||||
@@ -1420,7 +1420,7 @@ class FfiTrampolineDataDeserializationCluster : public DeserializationCluster {
|
||||
FfiTrampolineData::InstanceSize());
|
||||
d.ReadFromTo(data);
|
||||
data->untag()->callback_id_ =
|
||||
d_->kind() == Snapshot::kFullAOT ? d.ReadUnsigned() : 0;
|
||||
d_->kind() == Snapshot::kFullAOT ? d.Read<int32_t>() : -1;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -328,6 +328,23 @@ class CanonicalInstanceTraits {
|
||||
static ObjectPtr NewKey(const CanonicalInstanceKey& obj);
|
||||
};
|
||||
|
||||
struct CanonicalFfiCallbackFunctionTraits {
|
||||
static uint32_t Hash(const Object& key) { return Function::Cast(key).Hash(); }
|
||||
static const char* Name() { return "CanonicalFfiCallbackFunctionTraits"; }
|
||||
static bool IsMatch(const Object& x, const Object& y) {
|
||||
const auto& f1 = Function::Cast(x);
|
||||
const auto& f2 = Function::Cast(y);
|
||||
return (f1.FfiCallbackTarget() == f2.FfiCallbackTarget() &&
|
||||
f1.FfiCSignature() == f2.FfiCSignature() &&
|
||||
f1.FfiCallbackExceptionalReturn() ==
|
||||
f2.FfiCallbackExceptionalReturn());
|
||||
}
|
||||
static bool ReportStats() { return false; }
|
||||
};
|
||||
|
||||
using FfiCallbackFunctionSet =
|
||||
UnorderedHashSet<CanonicalFfiCallbackFunctionTraits>;
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // RUNTIME_VM_CANONICAL_TABLES_H_
|
||||
|
||||
@@ -2151,10 +2151,8 @@ class NativeEntryInstr : public FunctionEntryInstr {
|
||||
GraphEntryInstr* graph_entry,
|
||||
intptr_t block_id,
|
||||
intptr_t try_index,
|
||||
intptr_t deopt_id,
|
||||
intptr_t callback_id)
|
||||
intptr_t deopt_id)
|
||||
: FunctionEntryInstr(graph_entry, block_id, try_index, deopt_id),
|
||||
callback_id_(callback_id),
|
||||
marshaller_(marshaller) {}
|
||||
|
||||
DECLARE_INSTRUCTION(NativeEntry)
|
||||
@@ -2162,7 +2160,6 @@ class NativeEntryInstr : public FunctionEntryInstr {
|
||||
PRINT_TO_SUPPORT
|
||||
|
||||
#define FIELD_LIST(F) \
|
||||
F(const intptr_t, callback_id_) \
|
||||
F(const compiler::ffi::CallbackMarshaller&, marshaller_)
|
||||
|
||||
DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(NativeEntryInstr,
|
||||
@@ -9667,6 +9664,7 @@ class CheckNullInstr : public TemplateDefinition<1, Throws, Pure> {
|
||||
function_name_(function_name),
|
||||
exception_type_(exception_type) {
|
||||
ASSERT(function_name.IsNotTemporaryScopedHandle());
|
||||
ASSERT(function_name.IsSymbol());
|
||||
SetInputAt(0, value);
|
||||
}
|
||||
|
||||
|
||||
@@ -1636,6 +1636,8 @@ void NativeEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
reinterpret_cast<uword>(DLRT_GetThreadForNativeCallback)));
|
||||
}
|
||||
|
||||
const intptr_t callback_id = marshaller_.dart_signature().FfiCallbackId();
|
||||
|
||||
// Load the thread object. If we were called by a trampoline, the thread is
|
||||
// already loaded.
|
||||
if (!NativeCallbackTrampolines::Enabled()) {
|
||||
@@ -1644,7 +1646,7 @@ void NativeEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
__ EnterFrame(1 << FP, 0);
|
||||
__ ReserveAlignedFrameSpace(0);
|
||||
|
||||
__ LoadImmediate(R0, callback_id_);
|
||||
__ LoadImmediate(R0, callback_id);
|
||||
__ blx(R1);
|
||||
__ mov(THR, compiler::Operand(R0));
|
||||
|
||||
@@ -1689,7 +1691,7 @@ void NativeEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
compiler::target::GrowableObjectArray::data_offset());
|
||||
__ LoadFieldFromOffset(CODE_REG, R0,
|
||||
compiler::target::Array::data_offset() +
|
||||
callback_id_ * compiler::target::kWordSize);
|
||||
callback_id * compiler::target::kWordSize);
|
||||
|
||||
// Put the code object in the reserved slot.
|
||||
__ StoreToOffset(CODE_REG, FPREG,
|
||||
|
||||
@@ -1486,13 +1486,15 @@ void NativeEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
R1, reinterpret_cast<int64_t>(DLRT_GetThreadForNativeCallback));
|
||||
}
|
||||
|
||||
const intptr_t callback_id = marshaller_.dart_signature().FfiCallbackId();
|
||||
|
||||
if (!NativeCallbackTrampolines::Enabled()) {
|
||||
// Create another frame to align the frame before continuing in "native"
|
||||
// code.
|
||||
__ EnterFrame(0);
|
||||
__ ReserveAlignedFrameSpace(0);
|
||||
|
||||
__ LoadImmediate(R0, callback_id_);
|
||||
__ LoadImmediate(R0, callback_id);
|
||||
__ blr(R1);
|
||||
__ mov(THR, R0);
|
||||
|
||||
@@ -1549,7 +1551,7 @@ void NativeEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
__ LoadCompressedFieldFromOffset(
|
||||
CODE_REG, R0,
|
||||
compiler::target::Array::data_offset() +
|
||||
callback_id_ * compiler::target::kCompressedWordSize);
|
||||
callback_id * compiler::target::kCompressedWordSize);
|
||||
|
||||
// Put the code object in the reserved slot.
|
||||
__ StoreToOffset(CODE_REG, FPREG,
|
||||
|
||||
@@ -1174,6 +1174,8 @@ void NativeEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
__ pushl(ESI);
|
||||
__ pushl(EDI);
|
||||
|
||||
const intptr_t callback_id = marshaller_.dart_signature().FfiCallbackId();
|
||||
|
||||
// Load the thread object.
|
||||
//
|
||||
// Create another frame to align the frame before continuing in "native" code.
|
||||
@@ -1183,7 +1185,7 @@ void NativeEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
__ EnterFrame(0);
|
||||
__ ReserveAlignedFrameSpace(compiler::target::kWordSize);
|
||||
|
||||
__ movl(compiler::Address(SPREG, 0), compiler::Immediate(callback_id_));
|
||||
__ movl(compiler::Address(SPREG, 0), compiler::Immediate(callback_id));
|
||||
__ movl(EAX, compiler::Immediate(reinterpret_cast<intptr_t>(
|
||||
DLRT_GetThreadForNativeCallback)));
|
||||
__ call(EAX);
|
||||
@@ -1227,7 +1229,7 @@ void NativeEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
EAX, compiler::target::GrowableObjectArray::data_offset()));
|
||||
__ movl(CODE_REG, compiler::FieldAddress(
|
||||
EAX, compiler::target::Array::data_offset() +
|
||||
callback_id_ * compiler::target::kWordSize));
|
||||
callback_id * compiler::target::kWordSize));
|
||||
|
||||
// Put the code object in the reserved slot.
|
||||
__ movl(compiler::Address(FPREG,
|
||||
|
||||
@@ -1704,13 +1704,15 @@ void NativeEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
A1, reinterpret_cast<int64_t>(DLRT_GetThreadForNativeCallback));
|
||||
}
|
||||
|
||||
const intptr_t callback_id = marshaller_.dart_signature().FfiCallbackId();
|
||||
|
||||
if (!NativeCallbackTrampolines::Enabled()) {
|
||||
// Create another frame to align the frame before continuing in "native"
|
||||
// code.
|
||||
__ EnterFrame(0);
|
||||
__ ReserveAlignedFrameSpace(0);
|
||||
|
||||
__ LoadImmediate(A0, callback_id_);
|
||||
__ LoadImmediate(A0, callback_id);
|
||||
__ jalr(A1);
|
||||
__ mv(THR, A0);
|
||||
|
||||
@@ -1760,7 +1762,7 @@ void NativeEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
__ LoadCompressedFieldFromOffset(
|
||||
CODE_REG, A0,
|
||||
compiler::target::Array::data_offset() +
|
||||
callback_id_ * compiler::target::kCompressedWordSize);
|
||||
callback_id * compiler::target::kCompressedWordSize);
|
||||
|
||||
// Put the code object in the reserved slot.
|
||||
__ StoreToOffset(CODE_REG, FPREG,
|
||||
|
||||
@@ -242,15 +242,16 @@ void BranchInstr::ReadExtra(FlowGraphDeserializer* d) {
|
||||
template <>
|
||||
void FlowGraphSerializer::WriteTrait<const compiler::ffi::CallbackMarshaller&>::
|
||||
Write(FlowGraphSerializer* s, const compiler::ffi::CallbackMarshaller& x) {
|
||||
UNIMPLEMENTED();
|
||||
s->Write<const Function&>(x.dart_signature());
|
||||
}
|
||||
|
||||
template <>
|
||||
const compiler::ffi::CallbackMarshaller& FlowGraphDeserializer::ReadTrait<
|
||||
const compiler::ffi::CallbackMarshaller&>::Read(FlowGraphDeserializer* d) {
|
||||
UNIMPLEMENTED();
|
||||
const Function& dart_signature = d->Read<const Function&>();
|
||||
const char* error = nullptr;
|
||||
return *compiler::ffi::CallbackMarshaller::FromFunction(
|
||||
d->zone(), Function::null_function(), nullptr);
|
||||
d->zone(), dart_signature, &error);
|
||||
}
|
||||
|
||||
template <>
|
||||
@@ -830,14 +831,18 @@ void FlowGraphSerializer::WriteTrait<const Function&>::Write(
|
||||
return;
|
||||
}
|
||||
case UntaggedFunction::kFfiTrampoline: {
|
||||
if (x.FfiCallbackTarget() != Object::null()) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
s->Write<const String&>(String::Handle(zone, x.name()));
|
||||
s->Write<const FunctionType&>(FunctionType::Handle(zone, x.signature()));
|
||||
s->Write<const Function&>(Function::Handle(zone, x.FfiCallbackTarget()));
|
||||
s->Write<const FunctionType&>(
|
||||
FunctionType::Handle(zone, x.FfiCSignature()));
|
||||
s->Write<bool>(x.FfiIsLeaf());
|
||||
if (x.FfiCallbackTarget() != Object::null()) {
|
||||
s->Write<const Instance&>(
|
||||
Instance::Handle(zone, x.FfiCallbackExceptionalReturn()));
|
||||
} else {
|
||||
s->Write<const String&>(String::Handle(zone, x.name()));
|
||||
s->Write<const FunctionType&>(
|
||||
FunctionType::Handle(zone, x.signature()));
|
||||
s->Write<bool>(x.FfiIsLeaf());
|
||||
}
|
||||
return;
|
||||
}
|
||||
default:
|
||||
@@ -914,13 +919,22 @@ const Function& FlowGraphDeserializer::ReadTrait<const Function&>::Read(
|
||||
target.GetDynamicInvocationForwarder(name));
|
||||
}
|
||||
case UntaggedFunction::kFfiTrampoline: {
|
||||
const String& name = d->Read<const String&>();
|
||||
const FunctionType& signature = d->Read<const FunctionType&>();
|
||||
const Function& callback_target = d->Read<const Function&>();
|
||||
const FunctionType& c_signature = d->Read<const FunctionType&>();
|
||||
const bool is_leaf = d->Read<bool>();
|
||||
return Function::ZoneHandle(
|
||||
zone, compiler::ffi::TrampolineFunction(name, signature, c_signature,
|
||||
is_leaf));
|
||||
if (!callback_target.IsNull()) {
|
||||
const Instance& exceptional_return = d->Read<const Instance&>();
|
||||
return Function::ZoneHandle(
|
||||
zone, compiler::ffi::NativeCallbackFunction(
|
||||
c_signature, callback_target, exceptional_return,
|
||||
/*register_function=*/true));
|
||||
} else {
|
||||
const String& name = d->Read<const String&>();
|
||||
const FunctionType& signature = d->Read<const FunctionType&>();
|
||||
const bool is_leaf = d->Read<bool>();
|
||||
return Function::ZoneHandle(
|
||||
zone, compiler::ffi::TrampolineFunction(name, signature,
|
||||
c_signature, is_leaf));
|
||||
}
|
||||
}
|
||||
default:
|
||||
UNIMPLEMENTED();
|
||||
@@ -1981,6 +1995,7 @@ InstancePtr FlowGraphDeserializer::MaybeCanonicalize(
|
||||
V(Array, Object::null_array()) \
|
||||
V(Field, Field::Handle(d->zone())) \
|
||||
V(FunctionType, Object::null_function_type()) \
|
||||
V(Instance, Object::null_instance()) \
|
||||
V(String, Object::null_string()) \
|
||||
V(TypeArguments, Object::null_type_arguments()) \
|
||||
V(TypeParameters, TypeParameters::Handle(d->zone()))
|
||||
|
||||
@@ -88,6 +88,7 @@ class NativeCallingConvention;
|
||||
V(Environment*) \
|
||||
V(const Field&) \
|
||||
V(const ICData*) \
|
||||
V(const Instance&) \
|
||||
V(int8_t) \
|
||||
V(int16_t) \
|
||||
V(int32_t) \
|
||||
|
||||
@@ -1365,6 +1365,8 @@ void NativeEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
DLRT_GetThreadForNativeCallback)));
|
||||
}
|
||||
|
||||
const intptr_t callback_id = marshaller_.dart_signature().FfiCallbackId();
|
||||
|
||||
// Create another frame to align the frame before continuing in "native" code.
|
||||
// If we were called by a trampoline, it has already loaded the thread.
|
||||
if (!NativeCallbackTrampolines::Enabled()) {
|
||||
@@ -1372,7 +1374,7 @@ void NativeEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
__ ReserveAlignedFrameSpace(0);
|
||||
|
||||
COMPILE_ASSERT(RAX != CallingConventions::kArg1Reg);
|
||||
__ movq(CallingConventions::kArg1Reg, compiler::Immediate(callback_id_));
|
||||
__ movq(CallingConventions::kArg1Reg, compiler::Immediate(callback_id));
|
||||
__ CallCFunction(RAX);
|
||||
__ movq(THR, RAX);
|
||||
|
||||
@@ -1415,7 +1417,7 @@ void NativeEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
CODE_REG,
|
||||
compiler::FieldAddress(
|
||||
RAX, compiler::target::Array::data_offset() +
|
||||
callback_id_ * compiler::target::kCompressedWordSize));
|
||||
callback_id * compiler::target::kCompressedWordSize));
|
||||
|
||||
// Put the code object in the reserved slot.
|
||||
__ movq(compiler::Address(FPREG,
|
||||
|
||||
@@ -4,7 +4,9 @@
|
||||
|
||||
#include "vm/compiler/ffi/callback.h"
|
||||
|
||||
#include "vm/canonical_tables.h"
|
||||
#include "vm/class_finalizer.h"
|
||||
#include "vm/object_store.h"
|
||||
#include "vm/symbols.h"
|
||||
|
||||
namespace dart {
|
||||
@@ -15,34 +17,35 @@ namespace ffi {
|
||||
|
||||
FunctionPtr NativeCallbackFunction(const FunctionType& c_signature,
|
||||
const Function& dart_target,
|
||||
const Instance& exceptional_return) {
|
||||
const Instance& exceptional_return,
|
||||
bool register_function) {
|
||||
Thread* const thread = Thread::Current();
|
||||
const int32_t callback_id = thread->AllocateFfiCallbackId();
|
||||
Zone* const zone = thread->zone();
|
||||
Function& function = Function::Handle(zone);
|
||||
ASSERT(c_signature.IsCanonical());
|
||||
ASSERT(exceptional_return.IsSmi() || exceptional_return.IsCanonical());
|
||||
|
||||
// Create a new Function named '<target>_FfiCallback' and stick it in the
|
||||
// 'dart:ffi' library. Note that these functions will never be invoked by
|
||||
// Dart, so they may have duplicate names.
|
||||
Zone* const zone = thread->zone();
|
||||
const auto& name = String::Handle(
|
||||
zone, Symbols::FromConcat(thread, Symbols::FfiCallback(),
|
||||
String::Handle(zone, dart_target.name())));
|
||||
const Library& lib = Library::Handle(zone, Library::FfiLibrary());
|
||||
const Class& owner_class = Class::Handle(zone, lib.toplevel_class());
|
||||
auto& signature = FunctionType::Handle(zone, FunctionType::New());
|
||||
const Function& function = Function::Handle(
|
||||
zone, Function::New(signature, name, UntaggedFunction::kFfiTrampoline,
|
||||
/*is_static=*/true,
|
||||
/*is_const=*/false,
|
||||
/*is_abstract=*/false,
|
||||
/*is_external=*/false,
|
||||
/*is_native=*/false, owner_class,
|
||||
TokenPosition::kNoSource));
|
||||
function =
|
||||
Function::New(signature, name, UntaggedFunction::kFfiTrampoline,
|
||||
/*is_static=*/true,
|
||||
/*is_const=*/false,
|
||||
/*is_abstract=*/false,
|
||||
/*is_external=*/false,
|
||||
/*is_native=*/false, owner_class, TokenPosition::kNoSource);
|
||||
function.set_is_debuggable(false);
|
||||
|
||||
// Set callback-specific fields which the flow-graph builder needs to generate
|
||||
// the body.
|
||||
function.SetFfiCSignature(c_signature);
|
||||
function.SetFfiCallbackId(callback_id);
|
||||
function.SetFfiCallbackTarget(dart_target);
|
||||
|
||||
// We need to load the exceptional return value as a constant in the generated
|
||||
@@ -71,6 +74,18 @@ FunctionPtr NativeCallbackFunction(const FunctionType& c_signature,
|
||||
signature ^= ClassFinalizer::FinalizeType(signature);
|
||||
function.SetSignature(signature);
|
||||
|
||||
if (register_function) {
|
||||
ObjectStore* object_store = thread->isolate_group()->object_store();
|
||||
if (object_store->ffi_callback_functions() == Array::null()) {
|
||||
FfiCallbackFunctionSet set(
|
||||
HashTables::New<FfiCallbackFunctionSet>(/*initial_capacity=*/4));
|
||||
object_store->set_ffi_callback_functions(set.Release());
|
||||
}
|
||||
FfiCallbackFunctionSet set(object_store->ffi_callback_functions());
|
||||
function ^= set.InsertOrGet(function);
|
||||
object_store->set_ffi_callback_functions(set.Release());
|
||||
}
|
||||
|
||||
return function.ptr();
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,8 @@ namespace ffi {
|
||||
|
||||
FunctionPtr NativeCallbackFunction(const FunctionType& c_signature,
|
||||
const Function& dart_target,
|
||||
const Instance& exceptional_return);
|
||||
const Instance& exceptional_return,
|
||||
bool register_function);
|
||||
|
||||
} // namespace ffi
|
||||
|
||||
|
||||
@@ -6146,19 +6146,12 @@ Fragment StreamingFlowGraphBuilder::BuildFfiNativeCallbackFunction() {
|
||||
compiler::ffi::NativeFunctionTypeFromFunctionType(zone_, native_sig, &error);
|
||||
ReportIfNotNull(error);
|
||||
|
||||
const Function& result =
|
||||
Function::ZoneHandle(Z, compiler::ffi::NativeCallbackFunction(
|
||||
native_sig, target, exceptional_return));
|
||||
const Function& result = Function::ZoneHandle(
|
||||
Z,
|
||||
compiler::ffi::NativeCallbackFunction(
|
||||
native_sig, target, exceptional_return, /*register_function=*/true));
|
||||
code += Constant(result);
|
||||
|
||||
auto& ffi_callback_functions = GrowableObjectArray::Handle(Z);
|
||||
ffi_callback_functions ^= IG->object_store()->ffi_callback_functions();
|
||||
if (ffi_callback_functions.IsNull()) {
|
||||
ffi_callback_functions ^= GrowableObjectArray::New();
|
||||
IG->object_store()->set_ffi_callback_functions(ffi_callback_functions);
|
||||
}
|
||||
ffi_callback_functions.Add(result);
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
|
||||
@@ -4745,9 +4745,9 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfFfiCallback(const Function& function) {
|
||||
graph_entry_ =
|
||||
new (Z) GraphEntryInstr(*parsed_function_, Compiler::kNoOSRDeoptId);
|
||||
|
||||
auto* const native_entry = new (Z) NativeEntryInstr(
|
||||
marshaller, graph_entry_, AllocateBlockId(), CurrentTryIndex(),
|
||||
GetNextDeoptId(), function.FfiCallbackId());
|
||||
auto* const native_entry =
|
||||
new (Z) NativeEntryInstr(marshaller, graph_entry_, AllocateBlockId(),
|
||||
CurrentTryIndex(), GetNextDeoptId());
|
||||
|
||||
graph_entry_->set_normal_entry(native_entry);
|
||||
|
||||
@@ -4793,9 +4793,9 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfFfiCallback(const Function& function) {
|
||||
body += Drop();
|
||||
body += IntConstant(0);
|
||||
} else if (!marshaller.IsHandle(compiler::ffi::kResultIndex)) {
|
||||
body +=
|
||||
CheckNullOptimized(String::ZoneHandle(Z, String::New("return_value")),
|
||||
CheckNullInstr::kArgumentError);
|
||||
body += CheckNullOptimized(
|
||||
String::ZoneHandle(Z, Symbols::New(H.thread(), "return_value")),
|
||||
CheckNullInstr::kArgumentError);
|
||||
}
|
||||
|
||||
if (marshaller.IsCompound(compiler::ffi::kResultIndex)) {
|
||||
|
||||
+15
-9
@@ -7656,16 +7656,22 @@ bool Function::FfiCSignatureReturnsStruct() const {
|
||||
|
||||
int32_t Function::FfiCallbackId() const {
|
||||
ASSERT(IsFfiTrampoline());
|
||||
if (FfiCallbackTarget() == Object::null()) {
|
||||
return -1;
|
||||
}
|
||||
const Object& obj = Object::Handle(data());
|
||||
ASSERT(!obj.IsNull());
|
||||
return FfiTrampolineData::Cast(obj).callback_id();
|
||||
}
|
||||
|
||||
void Function::SetFfiCallbackId(int32_t value) const {
|
||||
ASSERT(IsFfiTrampoline());
|
||||
const Object& obj = Object::Handle(data());
|
||||
ASSERT(!obj.IsNull());
|
||||
FfiTrampolineData::Cast(obj).set_callback_id(value);
|
||||
const FfiTrampolineData& trampoline_data = FfiTrampolineData::Cast(obj);
|
||||
int32_t callback_id = trampoline_data.callback_id();
|
||||
#if defined(DART_PRECOMPILED_RUNTIME)
|
||||
ASSERT(callback_id >= 0);
|
||||
#else
|
||||
if (callback_id < 0) {
|
||||
callback_id = Thread::Current()->AllocateFfiCallbackId();
|
||||
trampoline_data.set_callback_id(callback_id);
|
||||
}
|
||||
#endif
|
||||
return callback_id;
|
||||
}
|
||||
|
||||
bool Function::FfiIsLeaf() const {
|
||||
@@ -10610,7 +10616,7 @@ FfiTrampolineDataPtr FfiTrampolineData::New() {
|
||||
FfiTrampolineData::kClassId, FfiTrampolineData::InstanceSize(),
|
||||
Heap::kOld, FfiTrampolineData::ContainsCompressedPointers());
|
||||
FfiTrampolineDataPtr data = static_cast<FfiTrampolineDataPtr>(raw);
|
||||
data->untag()->callback_id_ = 0;
|
||||
data->untag()->callback_id_ = -1;
|
||||
data->untag()->is_leaf_ = false;
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -2745,9 +2745,6 @@ class Function : public Object {
|
||||
// -1 for Dart -> native calls.
|
||||
int32_t FfiCallbackId() const;
|
||||
|
||||
// Can only be called on FFI trampolines.
|
||||
void SetFfiCallbackId(int32_t value) const;
|
||||
|
||||
// Can only be called on FFI trampolines.
|
||||
bool FfiIsLeaf() const;
|
||||
|
||||
|
||||
@@ -272,7 +272,7 @@ class ObjectPointerVisitor;
|
||||
RW(GrowableObjectArray, instructions_tables) \
|
||||
RW(Array, obfuscation_map) \
|
||||
RW(Array, loading_unit_uris) \
|
||||
RW(GrowableObjectArray, ffi_callback_functions) \
|
||||
RW(Array, ffi_callback_functions) \
|
||||
RW(Class, ffi_pointer_class) \
|
||||
RW(Class, ffi_native_type_class) \
|
||||
// Please remember the last entry must be referred in the 'to' function below.
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include "vm/program_visitor.h"
|
||||
|
||||
#include "vm/canonical_tables.h"
|
||||
#include "vm/closure_functions_cache.h"
|
||||
#include "vm/code_patcher.h"
|
||||
#include "vm/deopt_instructions.h"
|
||||
@@ -256,14 +257,16 @@ void ProgramVisitor::WalkProgram(Zone* zone,
|
||||
|
||||
// TODO(dartbug.com/43049): Use a more general solution and remove manual
|
||||
// tracking through object_store->ffi_callback_functions.
|
||||
auto& function = Function::Handle(zone);
|
||||
const auto& ffi_callback_entries = GrowableObjectArray::Handle(
|
||||
zone, object_store->ffi_callback_functions());
|
||||
if (!ffi_callback_entries.IsNull()) {
|
||||
for (intptr_t i = 0; i < ffi_callback_entries.Length(); i++) {
|
||||
function ^= ffi_callback_entries.At(i);
|
||||
if (object_store->ffi_callback_functions() != Array::null()) {
|
||||
auto& function = Function::Handle(zone);
|
||||
FfiCallbackFunctionSet set(object_store->ffi_callback_functions());
|
||||
FfiCallbackFunctionSet::Iterator it(&set);
|
||||
while (it.MoveNext()) {
|
||||
const intptr_t entry = it.Current();
|
||||
function ^= set.GetKey(entry);
|
||||
walker.AddToWorklist(function);
|
||||
}
|
||||
set.Release();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1431,9 +1431,9 @@ class UntaggedFfiTrampolineData : public UntaggedObject {
|
||||
// calls. The callback id is also used to for verifying that callbacks are
|
||||
// called on the correct isolate. See DLRT_VerifyCallbackIsolate for details.
|
||||
//
|
||||
// Will be 0 for non-callbacks. Check 'callback_target_' to determine if this
|
||||
// is a callback or not.
|
||||
uint32_t callback_id_;
|
||||
// Callback id is -1 for non-callbacks or when id is not allocated yet.
|
||||
// Check 'callback_target_' to determine if this is a callback or not.
|
||||
int32_t callback_id_;
|
||||
|
||||
// Whether this is a leaf call - i.e. one that doesn't call back into Dart.
|
||||
bool is_leaf_;
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
// VMOptions=--use-slow-path --write-protect-code --no-dual-map-code
|
||||
// VMOptions=--use-slow-path --write-protect-code --no-dual-map-code --stacktrace-every=100
|
||||
// VMOptions=--dwarf_stack_traces --no-retain_function_objects --no-retain_code_objects
|
||||
// VMOptions=--test_il_serialization
|
||||
// SharedObjects=ffi_test_functions
|
||||
|
||||
import 'dart:ffi';
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
// VMOptions=--use-slow-path --write-protect-code --no-dual-map-code
|
||||
// VMOptions=--use-slow-path --write-protect-code --no-dual-map-code --stacktrace-every=100
|
||||
// VMOptions=--dwarf_stack_traces --no-retain_function_objects --no-retain_code_objects
|
||||
// VMOptions=--test_il_serialization
|
||||
// SharedObjects=ffi_test_functions
|
||||
|
||||
import 'dart:ffi';
|
||||
|
||||
Reference in New Issue
Block a user