Skip to content

Commit 9b5abe5

Browse files
sjindel-googlecommit-bot@chromium.org
authored andcommitted
Re-land "[vm/ffi] Enable creating an ExternalTypedData from a Pointer."
Changes from original: - Finalize the specific ExternalTypedData class before allocating. - Add new import to all FFI patch files to not depend on the order the patch files are applied. Original CL is in patchset 1. Change-Id: I85c5e0d8bce15d8120575b6dbaae311c64aa6ec2 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/112242 Commit-Queue: Samir Jindel <[email protected]> Reviewed-by: Martin Kustermann <[email protected]> Reviewed-by: Vyacheslav Egorov <[email protected]>
1 parent f29f41f commit 9b5abe5

File tree

10 files changed

+448
-5
lines changed

10 files changed

+448
-5
lines changed

runtime/lib/ffi.cc

Lines changed: 89 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -568,7 +568,11 @@ DEFINE_NATIVE_ENTRY(Ffi_fromFunction, 1, 2) {
568568

569569
Class& native_function_class =
570570
Class::Handle(isolate->class_table()->At(kFfiNativeFunctionCid));
571-
native_function_class.EnsureIsFinalized(Thread::Current());
571+
const auto& error =
572+
Error::Handle(native_function_class.EnsureIsFinalized(Thread::Current()));
573+
if (!error.IsNull()) {
574+
Exceptions::PropagateError(error);
575+
}
572576

573577
Type& native_function_type = Type::Handle(
574578
Type::New(native_function_class, type_args, TokenPosition::kNoSource));
@@ -608,6 +612,90 @@ DEFINE_NATIVE_ENTRY(Ffi_fromFunction, 1, 2) {
608612
#endif
609613
}
610614

615+
DEFINE_NATIVE_ENTRY(Ffi_asExternalTypedData, 0, 2) {
616+
GET_NON_NULL_NATIVE_ARGUMENT(Pointer, pointer, arguments->NativeArgAt(0));
617+
GET_NON_NULL_NATIVE_ARGUMENT(Integer, count, arguments->NativeArgAt(1));
618+
const auto& pointer_type_arg = AbstractType::Handle(pointer.type_argument());
619+
const classid_t type_cid = pointer_type_arg.type_class_id();
620+
classid_t cid = 0;
621+
622+
switch (type_cid) {
623+
case kFfiInt8Cid:
624+
cid = kExternalTypedDataInt8ArrayCid;
625+
break;
626+
case kFfiUint8Cid:
627+
cid = kExternalTypedDataUint8ArrayCid;
628+
break;
629+
case kFfiInt16Cid:
630+
cid = kExternalTypedDataInt16ArrayCid;
631+
break;
632+
case kFfiUint16Cid:
633+
cid = kExternalTypedDataUint16ArrayCid;
634+
break;
635+
case kFfiInt32Cid:
636+
cid = kExternalTypedDataInt32ArrayCid;
637+
break;
638+
case kFfiUint32Cid:
639+
cid = kExternalTypedDataUint32ArrayCid;
640+
break;
641+
case kFfiInt64Cid:
642+
cid = kExternalTypedDataInt64ArrayCid;
643+
break;
644+
case kFfiUint64Cid:
645+
cid = kExternalTypedDataUint64ArrayCid;
646+
break;
647+
case kFfiIntPtrCid:
648+
cid = kWordSize == 4 ? kExternalTypedDataInt32ArrayCid
649+
: kExternalTypedDataInt64ArrayCid;
650+
break;
651+
case kFfiFloatCid:
652+
cid = kExternalTypedDataFloat32ArrayCid;
653+
break;
654+
case kFfiDoubleCid:
655+
cid = kExternalTypedDataFloat64ArrayCid;
656+
break;
657+
default: {
658+
const String& error = String::Handle(
659+
String::NewFormatted("Cannot create a TypedData from a Pointer to %s",
660+
pointer_type_arg.ToCString()));
661+
Exceptions::ThrowArgumentError(error);
662+
UNREACHABLE();
663+
}
664+
}
665+
666+
const intptr_t element_count = count.AsInt64Value();
667+
668+
if (element_count < 0 ||
669+
element_count > ExternalTypedData::MaxElements(cid)) {
670+
const String& error = String::Handle(
671+
String::NewFormatted("Count must be in the range [0, %" Pd "].",
672+
ExternalTypedData::MaxElements(cid)));
673+
Exceptions::ThrowArgumentError(error);
674+
}
675+
676+
// The address must be aligned by the element size.
677+
const intptr_t element_size = ExternalTypedData::ElementSizeFor(cid);
678+
if (!Utils::IsAligned(pointer.NativeAddress(), element_size)) {
679+
const String& error = String::Handle(
680+
String::NewFormatted("Pointer address must be aligned to a multiple of"
681+
"the element size (%" Pd ").",
682+
element_size));
683+
Exceptions::ThrowArgumentError(error);
684+
}
685+
686+
const auto& typed_data_class =
687+
Class::Handle(zone, isolate->class_table()->At(cid));
688+
const auto& error = Error::Handle(
689+
zone, typed_data_class.EnsureIsFinalized(Thread::Current()));
690+
if (!error.IsNull()) {
691+
Exceptions::PropagateError(error);
692+
}
693+
694+
return ExternalTypedData::New(
695+
cid, reinterpret_cast<uint8_t*>(pointer.NativeAddress()), element_count,
696+
Heap::kNew);
697+
}
698+
611699
#if defined(TARGET_ARCH_DBC)
612700

613701
void FfiMarshalledArguments::SetFunctionAddress(uint64_t value) const {

runtime/lib/ffi_dynamic_library_patch.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
44

5+
// All imports must be in all FFI patch files to not depend on the order
6+
// the patches are applied.
57
import "dart:_internal" show patch;
8+
import 'dart:typed_data' show TypedData;
69

710
DynamicLibrary _open(String name) native "Ffi_dl_open";
811

runtime/lib/ffi_native_type_patch.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
44

5+
// All imports must be in all FFI patch files to not depend on the order
6+
// the patches are applied.
57
import "dart:_internal" show patch;
8+
import 'dart:typed_data' show TypedData;
69

710
@patch
811
@pragma("vm:entry-point")

runtime/lib/ffi_patch.dart

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
44

5+
// All imports must be in all FFI patch files to not depend on the order
6+
// the patches are applied.
57
import "dart:_internal" show patch;
8+
import 'dart:typed_data' show TypedData;
69

710
@patch
811
int sizeOf<T extends NativeType>() native "Ffi_sizeOf";
@@ -17,6 +20,9 @@ Pointer<T> _fromAddress<T extends NativeType>(int ptr) native "Ffi_fromAddress";
1720
DS _asFunctionInternal<DS extends Function, NS extends Function>(
1821
Pointer<NativeFunction<NS>> ptr) native "Ffi_asFunctionInternal";
1922

23+
dynamic _asExternalTypedData(Pointer ptr, int count)
24+
native "Ffi_asExternalTypedData";
25+
2026
@patch
2127
@pragma("vm:entry-point")
2228
class Pointer<T extends NativeType> {
@@ -67,4 +73,8 @@ class Pointer<T extends NativeType> {
6773

6874
@patch
6975
void free() native "Ffi_free";
76+
77+
@patch
78+
TypedData asExternalTypedData({int count: 1}) =>
79+
_asExternalTypedData(this, count);
7080
}

runtime/vm/bootstrap_natives.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,7 @@ namespace dart {
388388
V(Ffi_dl_open, 1) \
389389
V(Ffi_dl_lookup, 2) \
390390
V(Ffi_dl_getHandle, 1) \
391+
V(Ffi_asExternalTypedData, 2) \
391392
V(TransferableTypedData_factory, 2) \
392393
V(TransferableTypedData_materialize, 1)
393394

sdk/lib/ffi/ffi.dart

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
/// {@nodoc}
77
library dart.ffi;
88

9+
import 'dart:typed_data' show TypedData;
10+
911
part "native_type.dart";
1012
part "annotations.dart";
1113
part "dynamic_library.dart";
@@ -91,6 +93,35 @@ class Pointer<T extends NativeType> extends NativeType {
9193
/// Note that this zeros out the address.
9294
external void free();
9395

96+
/// Creates an *external* typed data array backed by this pointer.
97+
///
98+
/// The typed data array returned is only valid for as long as the backing
99+
/// [Pointer]. Accessing any element of the type data array after this
100+
/// [Pointer] has been [Pointer.free()]d will cause undefined behavior.
101+
///
102+
/// Since [Pointer]s do not know their length, the size of the typed data is
103+
/// controlled by `count`, in units of the size of the native type for this
104+
/// [Pointer] (similarly to [Pointer.allocate]).
105+
///
106+
/// The kind of TypedData produced depends on the native type:
107+
///
108+
/// Pointer<Int8> -> Int8List
109+
/// Pointer<Uint8> -> Uint8List
110+
/// etc. up to Int64/Uint64
111+
/// Pointer<IntPtr> -> Int32List/Int64List depending on platform word size
112+
/// Pointer<Float> -> Float32List
113+
/// Pointer<Double> -> Float64List
114+
///
115+
/// Creation of a [Uint8ClampedList] is not supported. Creation of a typed
116+
/// data from a [Pointer] to any other native type is not supported.
117+
///
118+
/// The pointer must be aligned to a multiple of the native type's size.
119+
//
120+
// TODO(37773): Use extension methods to articulate more precise return types.
121+
// We should still keep this member though as a generic way to access a
122+
// Pointer of unknown type.
123+
external TypedData asExternalTypedData({int count: 1});
124+
94125
/// Equality for Pointers only depends on their address.
95126
bool operator ==(other) {
96127
if (other == null) return false;

sdk/lib/libraries.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,9 @@
6565
},
6666
"ffi": {
6767
"patches": [
68+
"../../runtime/lib/ffi_patch.dart",
6869
"../../runtime/lib/ffi_dynamic_library_patch.dart",
69-
"../../runtime/lib/ffi_native_type_patch.dart",
70-
"../../runtime/lib/ffi_patch.dart"
70+
"../../runtime/lib/ffi_native_type_patch.dart"
7171
],
7272
"uri": "ffi/ffi.dart"
7373
},

sdk/lib/libraries.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,9 +90,9 @@ vm:
9090
ffi:
9191
uri: "ffi/ffi.dart"
9292
patches:
93+
- "../../runtime/lib/ffi_patch.dart"
9394
- "../../runtime/lib/ffi_dynamic_library_patch.dart"
9495
- "../../runtime/lib/ffi_native_type_patch.dart"
95-
- "../../runtime/lib/ffi_patch.dart"
9696

9797
_http:
9898
uri: "_http/http.dart"

0 commit comments

Comments
 (0)