Skip to content

Commit 43aa985

Browse files
alexmarkovCommit Queue
authored andcommitted
[vm,dyn_modules] Support FFI loads/stores of AbiSpecificInteger in the interpreter
Also fix return type of _storeAbiSpecificInt / _storeAbiSpecificIntAtIndex (they actually return null, so declaring return type 'int' violates soundness of types). TEST=ci Change-Id: Ic7726e618a5d8dda189f81464c213629d70c23a1 Cq-Include-Trybots: luci.dart.try:vm-aot-dyn-linux-debug-x64-try,vm-aot-dyn-linux-product-x64-try,vm-dyn-linux-debug-x64-try,vm-dyn-mac-debug-arm64-try Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/447480 Reviewed-by: Tess Strickland <[email protected]> Commit-Queue: Alexander Markov <[email protected]>
1 parent 0b8e153 commit 43aa985

File tree

7 files changed

+156
-11
lines changed

7 files changed

+156
-11
lines changed

pkg/vm/testcases/transformations/ffi/abi_specific_int.dart.aot.expect

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,10 @@ final class WCharStruct extends ffi::Struct {
3030
return [@vm.inferred-type.metadata=int] ffi::_loadAbiSpecificInt<self::WChar>([@vm.direct-call.metadata=dart.ffi::_Compound._typedDataBase] this.{ffi::_Compound::_typedDataBase}{core::Object}, [@vm.direct-call.metadata=dart.core::_IntegerImplementation.+] [@vm.inferred-type.metadata=int (skip check)] [@vm.inferred-type.metadata=dart.core::_Smi (value: 0)] self::WCharStruct::a0#offsetOf.{core::num::+}([@vm.direct-call.metadata=dart.ffi::_Compound._offsetInBytes] [@vm.inferred-type.metadata=int?] this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num});
3131

3232
[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:1,getterSelectorId:2]
33-
[@vm.unboxing-info.metadata=(i)->i]
33+
[@vm.unboxing-info.metadata=(i)->b]
3434
@#C10
3535
set a0([@vm.inferred-arg-type.metadata=dart.core::_Smi] synthesized core::int #externalFieldValue) → void
36-
return [@vm.inferred-type.metadata=int] ffi::_storeAbiSpecificInt<self::WChar>([@vm.direct-call.metadata=dart.ffi::_Compound._typedDataBase] this.{ffi::_Compound::_typedDataBase}{core::Object}, [@vm.direct-call.metadata=dart.core::_IntegerImplementation.+] [@vm.inferred-type.metadata=int (skip check)] [@vm.inferred-type.metadata=dart.core::_Smi (value: 0)] self::WCharStruct::a0#offsetOf.{core::num::+}([@vm.direct-call.metadata=dart.ffi::_Compound._offsetInBytes] [@vm.inferred-type.metadata=int?] this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #externalFieldValue);
36+
return ffi::_storeAbiSpecificInt<self::WChar>([@vm.direct-call.metadata=dart.ffi::_Compound._typedDataBase] this.{ffi::_Compound::_typedDataBase}{core::Object}, [@vm.direct-call.metadata=dart.core::_IntegerImplementation.+] [@vm.inferred-type.metadata=int (skip check)] [@vm.inferred-type.metadata=dart.core::_Smi (value: 0)] self::WCharStruct::a0#offsetOf.{core::num::+}([@vm.direct-call.metadata=dart.ffi::_Compound._offsetInBytes] [@vm.inferred-type.metadata=int?] this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #externalFieldValue);
3737

3838
[@vm.inferred-return-type.metadata=dart.core::_Smi (value: 0)]
3939
[@vm.unboxing-info.metadata=()->i]

pkg/vm/testcases/transformations/ffi/abi_specific_int_incomplete.dart.aot.expect

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,10 @@ final class IncompleteStruct extends ffi::Struct {
3030
return [@vm.inferred-type.metadata=int] ffi::_loadAbiSpecificInt<self::Incomplete>([@vm.direct-call.metadata=dart.ffi::_Compound._typedDataBase] this.{ffi::_Compound::_typedDataBase}{core::Object}, [@vm.direct-call.metadata=dart.core::_IntegerImplementation.+] [@vm.inferred-type.metadata=int (skip check)] [@vm.inferred-type.metadata=dart.core::_Smi (value: 0)] self::IncompleteStruct::a0#offsetOf.{core::num::+}([@vm.direct-call.metadata=dart.ffi::_Compound._offsetInBytes] [@vm.inferred-type.metadata=int?] this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num});
3131

3232
[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:1,getterSelectorId:2]
33-
[@vm.unboxing-info.metadata=(i)->i]
33+
[@vm.unboxing-info.metadata=(i)->b]
3434
@#C8
3535
set a0([@vm.inferred-arg-type.metadata=dart.core::_Smi] synthesized core::int #externalFieldValue) → void
36-
return [@vm.inferred-type.metadata=int] ffi::_storeAbiSpecificInt<self::Incomplete>([@vm.direct-call.metadata=dart.ffi::_Compound._typedDataBase] this.{ffi::_Compound::_typedDataBase}{core::Object}, [@vm.direct-call.metadata=dart.core::_IntegerImplementation.+] [@vm.inferred-type.metadata=int (skip check)] [@vm.inferred-type.metadata=dart.core::_Smi (value: 0)] self::IncompleteStruct::a0#offsetOf.{core::num::+}([@vm.direct-call.metadata=dart.ffi::_Compound._offsetInBytes] [@vm.inferred-type.metadata=int?] this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #externalFieldValue);
36+
return ffi::_storeAbiSpecificInt<self::Incomplete>([@vm.direct-call.metadata=dart.ffi::_Compound._typedDataBase] this.{ffi::_Compound::_typedDataBase}{core::Object}, [@vm.direct-call.metadata=dart.core::_IntegerImplementation.+] [@vm.inferred-type.metadata=int (skip check)] [@vm.inferred-type.metadata=dart.core::_Smi (value: 0)] self::IncompleteStruct::a0#offsetOf.{core::num::+}([@vm.direct-call.metadata=dart.ffi::_Compound._offsetInBytes] [@vm.inferred-type.metadata=int?] this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #externalFieldValue);
3737

3838
[@vm.inferred-return-type.metadata=dart.core::_Smi (value: 0)]
3939
[@vm.unboxing-info.metadata=()->i]

pkg/vm/testcases/transformations/ffi/compound_array_elements.dart.aot.expect

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ static method main() → void {
101101
core::print(new ffi::_ArrayList::•<self::MyStruct>([@vm.direct-call.metadata=#lib::TestStruct.structArray] [@vm.inferred-type.metadata=dart.ffi::Array<#lib::MyStruct>] struct.{self::TestStruct::structArray}{ffi::Array<self::MyStruct>}, [@vm.inferred-type.metadata=dart.core::_Smi (value: 1)] self::MyStruct::#sizeOf, #C47));
102102
core::print(new ffi::_ArrayList::•<self::MyUnion>([@vm.direct-call.metadata=#lib::TestStruct.unionArray] [@vm.inferred-type.metadata=dart.ffi::Array<#lib::MyUnion>] struct.{self::TestStruct::unionArray}{ffi::Array<self::MyUnion>}, [@vm.inferred-type.metadata=dart.core::_Smi (value: 4)] self::MyUnion::#sizeOf, #C48));
103103
core::print(new ffi::_ArrayArrayList::•<ffi::Int8>([@vm.direct-call.metadata=#lib::TestStruct.arrayArray] [@vm.inferred-type.metadata=dart.ffi::Array<dart.ffi::Array<dart.ffi::Int8>>] struct.{self::TestStruct::arrayArray}{ffi::Array<ffi::Array<ffi::Int8>>}));
104-
core::print(new ffi::_AbiSpecificIntegerArrayList::•<ffi::WChar>([@vm.direct-call.metadata=#lib::TestStruct.abiSpecificIntegerArray] [@vm.inferred-type.metadata=dart.ffi::Array<dart.ffi::WChar>] struct.{self::TestStruct::abiSpecificIntegerArray}{ffi::Array<ffi::WChar>}, [@vm.closure-id=1](synthesized ffi::Array<ffi::WChar> #array, synthesized core::int #index) → core::int => [@vm.inferred-type.metadata=int] ffi::_loadAbiSpecificIntAtIndex<ffi::WChar>([@vm.direct-call.metadata=dart.ffi::_Compound._typedDataBase] #array.{ffi::_Compound::_typedDataBase}{core::Object}, [@vm.direct-call.metadata=dart.ffi::_Compound._offsetInBytes] [@vm.inferred-type.metadata=int?] #array.{ffi::_Compound::_offsetInBytes}{core::int}, #index), [@vm.closure-id=2](synthesized ffi::Array<ffi::WChar> #array, synthesized core::int #index, synthesized core::int? #value) → core::int => [@vm.inferred-type.metadata=int] ffi::_storeAbiSpecificIntAtIndex<ffi::WChar>([@vm.direct-call.metadata=dart.ffi::_Compound._typedDataBase] #array.{ffi::_Compound::_typedDataBase}{core::Object}, [@vm.direct-call.metadata=dart.ffi::_Compound._offsetInBytes] [@vm.inferred-type.metadata=int?] #array.{ffi::_Compound::_offsetInBytes}{core::int}, #index, #value)));
104+
core::print(new ffi::_AbiSpecificIntegerArrayList::•<ffi::WChar>([@vm.direct-call.metadata=#lib::TestStruct.abiSpecificIntegerArray] [@vm.inferred-type.metadata=dart.ffi::Array<dart.ffi::WChar>] struct.{self::TestStruct::abiSpecificIntegerArray}{ffi::Array<ffi::WChar>}, [@vm.closure-id=1](synthesized ffi::Array<ffi::WChar> #array, synthesized core::int #index) → core::int => [@vm.inferred-type.metadata=int] ffi::_loadAbiSpecificIntAtIndex<ffi::WChar>([@vm.direct-call.metadata=dart.ffi::_Compound._typedDataBase] #array.{ffi::_Compound::_typedDataBase}{core::Object}, [@vm.direct-call.metadata=dart.ffi::_Compound._offsetInBytes] [@vm.inferred-type.metadata=int?] #array.{ffi::_Compound::_offsetInBytes}{core::int}, #index), [@vm.closure-id=2](synthesized ffi::Array<ffi::WChar> #array, synthesized core::int #index, synthesized core::int? #value) → core::int => ffi::_storeAbiSpecificIntAtIndex<ffi::WChar>([@vm.direct-call.metadata=dart.ffi::_Compound._typedDataBase] #array.{ffi::_Compound::_typedDataBase}{core::Object}, [@vm.direct-call.metadata=dart.ffi::_Compound._offsetInBytes] [@vm.inferred-type.metadata=int?] #array.{ffi::_Compound::_offsetInBytes}{core::int}, #index, #value)));
105105
}
106106
constants {
107107
#C1 = "vm:deeply-immutable"

runtime/lib/ffi.cc

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "vm/compiler/assembler/assembler.h"
2323
#include "vm/compiler/ffi/callback.h"
2424
#include "vm/compiler/ffi/marshaller.h"
25+
#include "vm/compiler/ffi/native_type.h"
2526
#include "vm/compiler/jit/compiler.h"
2627
#endif // !defined(DART_PRECOMPILED_RUNTIME)
2728

@@ -67,6 +68,142 @@ DEFINE_NATIVE_ENTRY(Ffi_updateNativeCallableKeepIsolateAliveCounter, 1, 1) {
6768
return Object::null();
6869
}
6970

71+
static ObjectPtr LoadStoreAbiSpecificInt(Zone* zone,
72+
NativeArguments* arguments,
73+
bool is_load,
74+
bool at_index) {
75+
#if defined(DART_DYNAMIC_MODULES) && !defined(DART_PRECOMPILED_RUNTIME)
76+
const auto& type_args =
77+
TypeArguments::Handle(zone, arguments->NativeTypeArgs());
78+
const auto& base = Instance::CheckedHandle(zone, arguments->NativeArgAt(0));
79+
int64_t offset_in_bytes =
80+
Integer::CheckedHandle(zone, arguments->NativeArgAt(1)).Value();
81+
82+
const AbstractType& type_argument =
83+
AbstractType::Handle(zone, type_args.TypeAt(0));
84+
85+
// AbiSpecificTypes can have an incomplete mapping.
86+
const char* error = nullptr;
87+
const auto* native_type =
88+
compiler::ffi::NativeType::FromAbstractType(zone, type_argument, &error);
89+
if (error != nullptr) {
90+
const auto& language_error = Error::Handle(
91+
LanguageError::New(String::Handle(String::New(error, Heap::kOld)),
92+
Report::kError, Heap::kOld));
93+
Report::LongJump(language_error);
94+
}
95+
96+
if (at_index) {
97+
const int64_t index =
98+
Integer::CheckedHandle(zone, arguments->NativeArgAt(2)).Value();
99+
offset_in_bytes += index * native_type->SizeInBytes();
100+
}
101+
102+
int64_t value = 0;
103+
if (!is_load) {
104+
value =
105+
Integer::CheckedHandle(zone, arguments->NativeArgAt(at_index ? 3 : 2))
106+
.Value();
107+
}
108+
{
109+
NoSafepointScope no_safepoint;
110+
void* addr;
111+
if (base.IsPointer()) {
112+
addr = reinterpret_cast<void*>(Pointer::Cast(base).NativeAddress() +
113+
offset_in_bytes);
114+
} else if (base.IsTypedDataBase()) {
115+
addr = TypedDataBase::Cast(base).DataAddr(offset_in_bytes);
116+
} else {
117+
UNREACHABLE();
118+
}
119+
if (is_load) {
120+
ASSERT(native_type->IsPrimitive());
121+
switch (native_type->AsPrimitive().representation()) {
122+
case compiler::ffi::kInt8:
123+
value = *reinterpret_cast<int8_t*>(addr);
124+
break;
125+
case compiler::ffi::kInt16:
126+
value = *reinterpret_cast<int16_t*>(addr);
127+
break;
128+
case compiler::ffi::kInt32:
129+
value = *reinterpret_cast<int32_t*>(addr);
130+
break;
131+
case compiler::ffi::kInt64:
132+
value = *reinterpret_cast<int64_t*>(addr);
133+
break;
134+
case compiler::ffi::kUint8:
135+
value = *reinterpret_cast<uint8_t*>(addr);
136+
break;
137+
case compiler::ffi::kUint16:
138+
value = *reinterpret_cast<uint16_t*>(addr);
139+
break;
140+
case compiler::ffi::kUint32:
141+
value = *reinterpret_cast<uint32_t*>(addr);
142+
break;
143+
case compiler::ffi::kUint64:
144+
value = *reinterpret_cast<uint64_t*>(addr);
145+
break;
146+
default:
147+
UNREACHABLE();
148+
}
149+
} else {
150+
ASSERT(native_type->IsPrimitive());
151+
switch (native_type->AsPrimitive().representation()) {
152+
case compiler::ffi::kInt8:
153+
*reinterpret_cast<int8_t*>(addr) = static_cast<int8_t>(value);
154+
break;
155+
case compiler::ffi::kInt16:
156+
*reinterpret_cast<int16_t*>(addr) = static_cast<int16_t>(value);
157+
break;
158+
case compiler::ffi::kInt32:
159+
*reinterpret_cast<int32_t*>(addr) = static_cast<int32_t>(value);
160+
break;
161+
case compiler::ffi::kInt64:
162+
*reinterpret_cast<int64_t*>(addr) = value;
163+
break;
164+
case compiler::ffi::kUint8:
165+
*reinterpret_cast<uint8_t*>(addr) = static_cast<uint8_t>(value);
166+
break;
167+
case compiler::ffi::kUint16:
168+
*reinterpret_cast<uint16_t*>(addr) = static_cast<uint16_t>(value);
169+
break;
170+
case compiler::ffi::kUint32:
171+
*reinterpret_cast<uint32_t*>(addr) = static_cast<uint32_t>(value);
172+
break;
173+
case compiler::ffi::kUint64:
174+
*reinterpret_cast<uint64_t*>(addr) = static_cast<uint64_t>(value);
175+
break;
176+
default:
177+
UNREACHABLE();
178+
}
179+
}
180+
}
181+
return is_load ? Integer::New(value) : Object::null();
182+
#else
183+
UNIMPLEMENTED();
184+
#endif // defined(DART_DYNAMIC_MODULES) && !defined(DART_PRECOMPILED_RUNTIME)
185+
}
186+
187+
DEFINE_NATIVE_ENTRY(Ffi_loadAbiSpecificInt, 1, 2) {
188+
return LoadStoreAbiSpecificInt(zone, arguments, /*is_load=*/true,
189+
/*at_index=*/false);
190+
}
191+
192+
DEFINE_NATIVE_ENTRY(Ffi_loadAbiSpecificIntAtIndex, 1, 3) {
193+
return LoadStoreAbiSpecificInt(zone, arguments, /*is_load=*/true,
194+
/*at_index=*/true);
195+
}
196+
197+
DEFINE_NATIVE_ENTRY(Ffi_storeAbiSpecificInt, 1, 3) {
198+
return LoadStoreAbiSpecificInt(zone, arguments, /*is_load=*/false,
199+
/*at_index=*/false);
200+
}
201+
202+
DEFINE_NATIVE_ENTRY(Ffi_storeAbiSpecificIntAtIndex, 1, 4) {
203+
return LoadStoreAbiSpecificInt(zone, arguments, /*is_load=*/false,
204+
/*at_index=*/true);
205+
}
206+
70207
DEFINE_NATIVE_ENTRY(DartNativeApiFunctionPointer, 0, 1) {
71208
GET_NON_NULL_NATIVE_ARGUMENT(String, name_dart, arguments->NativeArgAt(0));
72209
const char* name = name_dart.ToCString();

runtime/vm/bootstrap_natives.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,10 @@ namespace dart {
303303
V(Ffi_dl_processLibrary, 0) \
304304
V(Ffi_dl_executableLibrary, 0) \
305305
V(Ffi_GetFfiNativeResolver, 0) \
306+
V(Ffi_loadAbiSpecificInt, 2) \
307+
V(Ffi_loadAbiSpecificIntAtIndex, 3) \
308+
V(Ffi_storeAbiSpecificInt, 3) \
309+
V(Ffi_storeAbiSpecificIntAtIndex, 4) \
306310
V(DartApiDLInitializeData, 0) \
307311
V(DartApiDLMajorVersion, 0) \
308312
V(DartApiDLMinorVersion, 0) \

runtime/vm/compiler/recognized_methods_list.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -130,9 +130,9 @@ namespace dart {
130130
FfiNativeIsolateGroupBoundCallbackFunction, 0xc20a0b32) \
131131
V(FfiLibrary, ::, _nativeIsolateGroupBoundClosureFunction, \
132132
FfiNativeIsolateGroupBoundClosureFunction, 0x0714be84) \
133-
V(FfiLibrary, ::, _loadAbiSpecificInt, FfiLoadAbiSpecificInt, 0x6abf70a6) \
133+
V(FfiLibrary, ::, _loadAbiSpecificInt, FfiLoadAbiSpecificInt, 0x6abf7467) \
134134
V(FfiLibrary, ::, _loadAbiSpecificIntAtIndex, FfiLoadAbiSpecificIntAtIndex, \
135-
0xc188dd75) \
135+
0xc188e136) \
136136
V(FfiLibrary, ::, _loadInt8, FfiLoadInt8, 0xe4acfa39) \
137137
V(FfiLibrary, ::, _loadInt16, FfiLoadInt16, 0xefe48685) \
138138
V(FfiLibrary, ::, _loadInt32, FfiLoadInt32, 0xea00b1ac) \
@@ -146,9 +146,9 @@ namespace dart {
146146
V(FfiLibrary, ::, _loadDouble, FfiLoadDouble, 0xeaad7eac) \
147147
V(FfiLibrary, ::, _loadDoubleUnaligned, FfiLoadDoubleUnaligned, 0xf5f52363) \
148148
V(FfiLibrary, ::, _loadPointer, FfiLoadPointer, 0x8a1d0159) \
149-
V(FfiLibrary, ::, _storeAbiSpecificInt, FfiStoreAbiSpecificInt, 0xaa7305ae) \
149+
V(FfiLibrary, ::, _storeAbiSpecificInt, FfiStoreAbiSpecificInt, 0x4cc50c5e) \
150150
V(FfiLibrary, ::, _storeAbiSpecificIntAtIndex, \
151-
FfiStoreAbiSpecificIntAtIndex, 0x258c6495) \
151+
FfiStoreAbiSpecificIntAtIndex, 0x326439bf) \
152152
V(FfiLibrary, ::, _storeInt8, FfiStoreInt8, 0xeea241c5) \
153153
V(FfiLibrary, ::, _storeInt16, FfiStoreInt16, 0xdb5cf594) \
154154
V(FfiLibrary, ::, _storeInt32, FfiStoreInt32, 0xd4dab471) \

sdk/lib/_internal/vm/lib/ffi_patch.dart

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,7 @@ external int _loadUint64(Object typedDataBase, int offsetInBytes);
517517
@pragma("vm:recognized", "other")
518518
@pragma("vm:idempotent")
519519
@pragma("vm:prefer-inline")
520+
@pragma("vm:external-name", "Ffi_loadAbiSpecificInt")
520521
external int _loadAbiSpecificInt<T extends AbiSpecificInteger>(
521522
Object typedDataBase,
522523
int offsetInBytes,
@@ -525,6 +526,7 @@ external int _loadAbiSpecificInt<T extends AbiSpecificInteger>(
525526
@pragma("vm:recognized", "other")
526527
@pragma("vm:idempotent")
527528
@pragma("vm:prefer-inline")
529+
@pragma("vm:external-name", "Ffi_loadAbiSpecificIntAtIndex")
528530
external int _loadAbiSpecificIntAtIndex<T extends AbiSpecificInteger>(
529531
Object typedDataBase,
530532
int offsetInBytes,
@@ -610,7 +612,8 @@ external void _storeUint64(Object typedDataBase, int offsetInBytes, int value);
610612
@pragma("vm:recognized", "other")
611613
@pragma("vm:idempotent")
612614
@pragma("vm:prefer-inline")
613-
external int _storeAbiSpecificInt<T extends AbiSpecificInteger>(
615+
@pragma("vm:external-name", "Ffi_storeAbiSpecificInt")
616+
external void _storeAbiSpecificInt<T extends AbiSpecificInteger>(
614617
Object typedDataBase,
615618
int offsetInBytes,
616619
int value,
@@ -619,7 +622,8 @@ external int _storeAbiSpecificInt<T extends AbiSpecificInteger>(
619622
@pragma("vm:recognized", "other")
620623
@pragma("vm:idempotent")
621624
@pragma("vm:prefer-inline")
622-
external int _storeAbiSpecificIntAtIndex<T extends AbiSpecificInteger>(
625+
@pragma("vm:external-name", "Ffi_storeAbiSpecificIntAtIndex")
626+
external void _storeAbiSpecificIntAtIndex<T extends AbiSpecificInteger>(
623627
Object typedDataBase,
624628
int offsetInBytes,
625629
int index,

0 commit comments

Comments
 (0)