Version 2.16.0-58.0.dev
Merge commit '35202a3c5fd3d4ab80ba51d60f87b42068f1bb3a' into 'dev'
diff --git a/benchmarks/FfiAsTypedList/dart/FfiAsTypedList.dart b/benchmarks/FfiAsTypedList/dart/FfiAsTypedList.dart
new file mode 100644
index 0000000..f32f5d0
--- /dev/null
+++ b/benchmarks/FfiAsTypedList/dart/FfiAsTypedList.dart
@@ -0,0 +1,49 @@
+// Copyright (c) 2021, 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.
+
+// Micro-benchmark for creating TypeData lists from Pointers.
+//
+// The FfiMemory benchmark tests accessing memory through TypedData.
+
+import 'dart:ffi';
+
+import 'package:benchmark_harness/benchmark_harness.dart';
+import 'package:ffi/ffi.dart';
+
+//
+// Benchmark fixture.
+//
+
+// Number of repeats: 1000
+const N = 1000;
+
+class FromPointerInt8 extends BenchmarkBase {
+ Pointer<Int8> pointer = nullptr;
+ FromPointerInt8() : super('FfiAsTypedList.FromPointerInt8');
+
+ @override
+ void setup() => pointer = calloc(1);
+ @override
+ void teardown() => calloc.free(pointer);
+
+ @override
+ void run() {
+ for (var i = 0; i < N; i++) {
+ pointer.asTypedList(1);
+ }
+ }
+}
+
+//
+// Main driver.
+//
+
+void main() {
+ final benchmarks = [
+ () => FromPointerInt8(),
+ ];
+ for (final benchmark in benchmarks) {
+ benchmark().report();
+ }
+}
diff --git a/benchmarks/FfiAsTypedList/dart2/FfiAsTypedList.dart b/benchmarks/FfiAsTypedList/dart2/FfiAsTypedList.dart
new file mode 100644
index 0000000..bab621d
--- /dev/null
+++ b/benchmarks/FfiAsTypedList/dart2/FfiAsTypedList.dart
@@ -0,0 +1,51 @@
+// Copyright (c) 2021, 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.
+
+// Micro-benchmark for creating TypeData lists from Pointers.
+//
+// The FfiMemory benchmark tests accessing memory through TypedData.
+
+// @dart=2.9
+
+import 'dart:ffi';
+
+import 'package:benchmark_harness/benchmark_harness.dart';
+import 'package:ffi/ffi.dart';
+
+//
+// Benchmark fixture.
+//
+
+// Number of repeats: 1000
+const N = 1000;
+
+class FromPointerInt8 extends BenchmarkBase {
+ Pointer<Int8> pointer = nullptr;
+ FromPointerInt8() : super('FfiAsTypedList.FromPointerInt8');
+
+ @override
+ void setup() => pointer = calloc(1);
+ @override
+ void teardown() => calloc.free(pointer);
+
+ @override
+ void run() {
+ for (var i = 0; i < N; i++) {
+ pointer.asTypedList(1);
+ }
+ }
+}
+
+//
+// Main driver.
+//
+
+void main() {
+ final benchmarks = [
+ () => FromPointerInt8(),
+ ];
+ for (final benchmark in benchmarks) {
+ benchmark().report();
+ }
+}
diff --git a/pkg/test_runner/lib/src/fuchsia.dart b/pkg/test_runner/lib/src/fuchsia.dart
index a3880c5..aeeab96 100644
--- a/pkg/test_runner/lib/src/fuchsia.dart
+++ b/pkg/test_runner/lib/src/fuchsia.dart
@@ -11,11 +11,13 @@
class FuchsiaEmulator {
static final Uri toolsDir =
+ Repository.uri.resolve('third_party/fuchsia/sdk/linux/tools/x64/');
+ static final Uri scriptsDir =
Repository.uri.resolve('third_party/fuchsia/sdk/linux/bin/');
- static final String femuTool = toolsDir.resolve('femu.sh').toFilePath();
- static final String fserveTool = toolsDir.resolve('fserve.sh').toFilePath();
- static final String fpubTool = toolsDir.resolve('fpublish.sh').toFilePath();
- static final String fsshTool = toolsDir.resolve('fssh.sh').toFilePath();
+ static final String femuTool = scriptsDir.resolve('femu.sh').toFilePath();
+ static final String fserveTool = toolsDir.resolve('fserve').toFilePath();
+ static final String fpubTool = toolsDir.resolve('fpublish').toFilePath();
+ static final String fsshTool = toolsDir.resolve('fssh').toFilePath();
static final RegExp emulatorReadyPattern =
RegExp(r'Using unique host name (.+)\.local\.');
static final RegExp emulatorPidPattern =
diff --git a/runtime/lib/ffi.cc b/runtime/lib/ffi.cc
index 239f758..9f0bf75 100644
--- a/runtime/lib/ffi.cc
+++ b/runtime/lib/ffi.cc
@@ -68,91 +68,10 @@
UNREACHABLE();
}
-DEFINE_NATIVE_ENTRY(Ffi_asExternalTypedData, 0, 2) {
- GET_NON_NULL_NATIVE_ARGUMENT(Pointer, pointer, arguments->NativeArgAt(0));
- GET_NON_NULL_NATIVE_ARGUMENT(Integer, count, arguments->NativeArgAt(1));
- const auto& pointer_type_arg = AbstractType::Handle(pointer.type_argument());
- const classid_t type_cid = pointer_type_arg.type_class_id();
- classid_t cid = 0;
-
- switch (type_cid) {
- case kFfiInt8Cid:
- cid = kExternalTypedDataInt8ArrayCid;
- break;
- case kFfiUint8Cid:
- cid = kExternalTypedDataUint8ArrayCid;
- break;
- case kFfiInt16Cid:
- cid = kExternalTypedDataInt16ArrayCid;
- break;
- case kFfiUint16Cid:
- cid = kExternalTypedDataUint16ArrayCid;
- break;
- case kFfiInt32Cid:
- cid = kExternalTypedDataInt32ArrayCid;
- break;
- case kFfiUint32Cid:
- cid = kExternalTypedDataUint32ArrayCid;
- break;
- case kFfiInt64Cid:
- cid = kExternalTypedDataInt64ArrayCid;
- break;
- case kFfiUint64Cid:
- cid = kExternalTypedDataUint64ArrayCid;
- break;
- case kFfiIntPtrCid:
- cid = kWordSize == 4 ? kExternalTypedDataInt32ArrayCid
- : kExternalTypedDataInt64ArrayCid;
- break;
- case kFfiFloatCid:
- cid = kExternalTypedDataFloat32ArrayCid;
- break;
- case kFfiDoubleCid:
- cid = kExternalTypedDataFloat64ArrayCid;
- break;
- default: {
- const String& error = String::Handle(
- String::NewFormatted("Cannot create a TypedData from a Pointer to %s",
- pointer_type_arg.ToCString()));
- Exceptions::ThrowArgumentError(error);
- UNREACHABLE();
- }
- }
-
- const intptr_t element_count = count.AsInt64Value();
-
- if (element_count < 0 ||
- element_count > ExternalTypedData::MaxElements(cid)) {
- const String& error = String::Handle(
- String::NewFormatted("Count must be in the range [0, %" Pd "].",
- ExternalTypedData::MaxElements(cid)));
- Exceptions::ThrowArgumentError(error);
- }
-
- // The address must be aligned by the element size.
- const intptr_t element_size = ExternalTypedData::ElementSizeFor(cid);
- if (!Utils::IsAligned(pointer.NativeAddress(), element_size)) {
- const String& error = String::Handle(
- String::NewFormatted("Pointer address must be aligned to a multiple of"
- "the element size (%" Pd ").",
- element_size));
- Exceptions::ThrowArgumentError(error);
- }
-
- const auto& typed_data_class =
- Class::Handle(zone, isolate->group()->class_table()->At(cid));
- const auto& error =
- Error::Handle(zone, typed_data_class.EnsureIsAllocateFinalized(thread));
- if (!error.IsNull()) {
- Exceptions::PropagateError(error);
- }
-
- // We disable msan initialization check because the memory may not be
- // initialized yet - dart code might do that later on.
- return ExternalTypedData::New(
- cid, reinterpret_cast<uint8_t*>(pointer.NativeAddress()), element_count,
- Heap::kNew, /*perform_eager_msan_initialization_check=*/false);
-}
+#define DEFINE_NATIVE_ENTRY_AS_EXTERNAL_TYPED_DATA(type) \
+ DEFINE_NATIVE_ENTRY(Ffi_asExternalTypedData##type, 0, 2) { UNREACHABLE(); }
+CLASS_LIST_FFI_NUMERIC_FIXED_SIZE(DEFINE_NATIVE_ENTRY_AS_EXTERNAL_TYPED_DATA)
+#undef DEFINE_NATIVE_ENTRY_AS_EXTERNAL_TYPED_DATA
DEFINE_NATIVE_ENTRY(Ffi_nativeCallbackFunction, 1, 2) {
#if defined(DART_PRECOMPILED_RUNTIME) || defined(DART_PRECOMPILER)
diff --git a/runtime/tools/ffi/sdk_lib_ffi_generator.dart b/runtime/tools/ffi/sdk_lib_ffi_generator.dart
index d44c2ec..d32b0a1 100644
--- a/runtime/tools/ffi/sdk_lib_ffi_generator.dart
+++ b/runtime/tools/ffi/sdk_lib_ffi_generator.dart
@@ -223,7 +223,13 @@
? ""
: """
@patch
- $typedListType asTypedList(int elements) => _asExternalTypedData(this, elements);
+ $typedListType asTypedList(int length) {
+ ArgumentError.checkNotNull(this, "Pointer<$nativeType>");
+ ArgumentError.checkNotNull(length, "length");
+ _checkExternalTypedDataLength(length, $elementSize);
+ _checkPointerAlignment(address, $elementSize);
+ return _asExternalTypedData$nativeType(this, length);
+ }
""";
if (container == "Pointer") {
diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h
index 46b44a3..adade03 100644
--- a/runtime/vm/bootstrap_natives.h
+++ b/runtime/vm/bootstrap_natives.h
@@ -400,7 +400,16 @@
V(Ffi_dl_lookup, 2) \
V(Ffi_dl_getHandle, 1) \
V(Ffi_dl_providesSymbol, 2) \
- V(Ffi_asExternalTypedData, 2) \
+ V(Ffi_asExternalTypedDataInt8, 2) \
+ V(Ffi_asExternalTypedDataInt16, 2) \
+ V(Ffi_asExternalTypedDataInt32, 2) \
+ V(Ffi_asExternalTypedDataInt64, 2) \
+ V(Ffi_asExternalTypedDataUint8, 2) \
+ V(Ffi_asExternalTypedDataUint16, 2) \
+ V(Ffi_asExternalTypedDataUint32, 2) \
+ V(Ffi_asExternalTypedDataUint64, 2) \
+ V(Ffi_asExternalTypedDataFloat, 2) \
+ V(Ffi_asExternalTypedDataDouble, 2) \
V(Ffi_dl_processLibrary, 0) \
V(Ffi_dl_executableLibrary, 0) \
V(Ffi_GetFfiNativeResolver, 0) \
diff --git a/runtime/vm/class_id.h b/runtime/vm/class_id.h
index bc52316..9b647b3 100644
--- a/runtime/vm/class_id.h
+++ b/runtime/vm/class_id.h
@@ -140,7 +140,7 @@
V(Int32x4Array) \
V(Float64x2Array)
-#define CLASS_LIST_FFI_NUMERIC(V) \
+#define CLASS_LIST_FFI_NUMERIC_FIXED_SIZE(V) \
V(Int8) \
V(Int16) \
V(Int32) \
@@ -149,10 +149,13 @@
V(Uint16) \
V(Uint32) \
V(Uint64) \
- V(IntPtr) \
V(Float) \
V(Double)
+#define CLASS_LIST_FFI_NUMERIC(V) \
+ CLASS_LIST_FFI_NUMERIC_FIXED_SIZE(V) \
+ V(IntPtr)
+
#define CLASS_LIST_FFI_TYPE_MARKER(V) \
CLASS_LIST_FFI_NUMERIC(V) \
V(Void) \
diff --git a/runtime/vm/compiler/ffi/recognized_method.cc b/runtime/vm/compiler/ffi/recognized_method.cc
index fa93dd3..f2fd7b6 100644
--- a/runtime/vm/compiler/ffi/recognized_method.cc
+++ b/runtime/vm/compiler/ffi/recognized_method.cc
@@ -45,6 +45,33 @@
}
}
+classid_t ElementExternalTypedDataCid(classid_t class_id) {
+ switch (class_id) {
+ case kFfiInt8Cid:
+ return kExternalTypedDataInt8ArrayCid;
+ case kFfiUint8Cid:
+ return kExternalTypedDataUint8ArrayCid;
+ case kFfiInt16Cid:
+ return kExternalTypedDataInt16ArrayCid;
+ case kFfiUint16Cid:
+ return kExternalTypedDataUint16ArrayCid;
+ case kFfiInt32Cid:
+ return kExternalTypedDataInt32ArrayCid;
+ case kFfiUint32Cid:
+ return kExternalTypedDataUint32ArrayCid;
+ case kFfiInt64Cid:
+ return kExternalTypedDataInt64ArrayCid;
+ case kFfiUint64Cid:
+ return kExternalTypedDataUint64ArrayCid;
+ case kFfiFloatCid:
+ return kExternalTypedDataFloat32ArrayCid;
+ case kFfiDoubleCid:
+ return kExternalTypedDataFloat64ArrayCid;
+ default:
+ UNREACHABLE();
+ }
+}
+
classid_t RecognizedMethodTypeArgCid(MethodRecognizer::Kind kind) {
switch (kind) {
#define LOAD_STORE(type) \
@@ -62,6 +89,11 @@
case MethodRecognizer::kFfiLoadPointer:
case MethodRecognizer::kFfiStorePointer:
return kPointerCid;
+#define AS_EXTERNAL_TYPED_DATA(type) \
+ case MethodRecognizer::kFfiAsExternalTypedData##type: \
+ return kFfi##type##Cid;
+ CLASS_LIST_FFI_NUMERIC_FIXED_SIZE(AS_EXTERNAL_TYPED_DATA)
+#undef AS_EXTERNAL_TYPED_DATA
default:
UNREACHABLE();
}
diff --git a/runtime/vm/compiler/ffi/recognized_method.h b/runtime/vm/compiler/ffi/recognized_method.h
index 993306e..98f4a31 100644
--- a/runtime/vm/compiler/ffi/recognized_method.h
+++ b/runtime/vm/compiler/ffi/recognized_method.h
@@ -23,6 +23,10 @@
// TypedData class id for a NativeType type, except for Void and NativeFunction.
classid_t ElementTypedDataCid(classid_t class_id);
+// ExternalTypedData class id for a NativeType type, except for Void,
+// NativeFunction, IntPtr and Pointer.
+classid_t ElementExternalTypedDataCid(classid_t class_id);
+
// Returns the kFFi<type>Cid for the recognized load/store method [kind].
classid_t RecognizedMethodTypeArgCid(MethodRecognizer::Kind kind);
diff --git a/runtime/vm/compiler/frontend/kernel_to_il.cc b/runtime/vm/compiler/frontend/kernel_to_il.cc
index 37df7be..9b0e7cf 100644
--- a/runtime/vm/compiler/frontend/kernel_to_il.cc
+++ b/runtime/vm/compiler/frontend/kernel_to_il.cc
@@ -838,36 +838,20 @@
case MethodRecognizer::kTypedData_Float32x4Array_factory:
case MethodRecognizer::kTypedData_Int32x4Array_factory:
case MethodRecognizer::kTypedData_Float64x2Array_factory:
- case MethodRecognizer::kFfiLoadInt8:
- case MethodRecognizer::kFfiLoadInt16:
- case MethodRecognizer::kFfiLoadInt32:
- case MethodRecognizer::kFfiLoadInt64:
- case MethodRecognizer::kFfiLoadUint8:
- case MethodRecognizer::kFfiLoadUint16:
- case MethodRecognizer::kFfiLoadUint32:
- case MethodRecognizer::kFfiLoadUint64:
- case MethodRecognizer::kFfiLoadIntPtr:
- case MethodRecognizer::kFfiLoadFloat:
- case MethodRecognizer::kFfiLoadFloatUnaligned:
- case MethodRecognizer::kFfiLoadDouble:
- case MethodRecognizer::kFfiLoadDoubleUnaligned:
- case MethodRecognizer::kFfiLoadPointer:
- case MethodRecognizer::kFfiStoreInt8:
- case MethodRecognizer::kFfiStoreInt16:
- case MethodRecognizer::kFfiStoreInt32:
- case MethodRecognizer::kFfiStoreInt64:
- case MethodRecognizer::kFfiStoreUint8:
- case MethodRecognizer::kFfiStoreUint16:
- case MethodRecognizer::kFfiStoreUint32:
- case MethodRecognizer::kFfiStoreUint64:
- case MethodRecognizer::kFfiStoreIntPtr:
- case MethodRecognizer::kFfiStoreFloat:
- case MethodRecognizer::kFfiStoreFloatUnaligned:
- case MethodRecognizer::kFfiStoreDouble:
- case MethodRecognizer::kFfiStoreDoubleUnaligned:
- case MethodRecognizer::kFfiStorePointer:
+#define FFI_LOAD_STORE(type) \
+ case MethodRecognizer::kFfiLoad##type: \
+ case MethodRecognizer::kFfiStore##type:
+ CLASS_LIST_FFI_NUMERIC(FFI_LOAD_STORE)
+ FFI_LOAD_STORE(FloatUnaligned)
+ FFI_LOAD_STORE(DoubleUnaligned)
+ FFI_LOAD_STORE(Pointer)
+#undef FFI_LOAD_STORE
case MethodRecognizer::kFfiFromAddress:
case MethodRecognizer::kFfiGetAddress:
+#define FFI_AS_EXTERNAL_TYPED_DATA(type) \
+ case MethodRecognizer::kFfiAsExternalTypedData##type:
+ CLASS_LIST_FFI_NUMERIC_FIXED_SIZE(FFI_AS_EXTERNAL_TYPED_DATA)
+#undef FFI_AS_EXTERNAL_TYPED_DATA
case MethodRecognizer::kGetNativeField:
case MethodRecognizer::kObjectEquals:
case MethodRecognizer::kStringBaseLength:
@@ -1347,20 +1331,13 @@
ASSERT_EQUAL(function.NumParameters(), 0);
body += IntConstant(static_cast<int64_t>(compiler::ffi::TargetAbi()));
break;
- case MethodRecognizer::kFfiLoadInt8:
- case MethodRecognizer::kFfiLoadInt16:
- case MethodRecognizer::kFfiLoadInt32:
- case MethodRecognizer::kFfiLoadInt64:
- case MethodRecognizer::kFfiLoadUint8:
- case MethodRecognizer::kFfiLoadUint16:
- case MethodRecognizer::kFfiLoadUint32:
- case MethodRecognizer::kFfiLoadUint64:
- case MethodRecognizer::kFfiLoadIntPtr:
- case MethodRecognizer::kFfiLoadFloat:
- case MethodRecognizer::kFfiLoadFloatUnaligned:
- case MethodRecognizer::kFfiLoadDouble:
- case MethodRecognizer::kFfiLoadDoubleUnaligned:
- case MethodRecognizer::kFfiLoadPointer: {
+#define FFI_LOAD(type) case MethodRecognizer::kFfiLoad##type:
+ CLASS_LIST_FFI_NUMERIC(FFI_LOAD)
+ FFI_LOAD(FloatUnaligned)
+ FFI_LOAD(DoubleUnaligned)
+ FFI_LOAD(Pointer)
+#undef FFI_LOAD
+ {
const classid_t ffi_type_arg_cid =
compiler::ffi::RecognizedMethodTypeArgCid(kind);
const AlignmentType alignment =
@@ -1426,20 +1403,13 @@
}
body += DropTempsPreserveTop(1); // Drop [arg_offset].
} break;
- case MethodRecognizer::kFfiStoreInt8:
- case MethodRecognizer::kFfiStoreInt16:
- case MethodRecognizer::kFfiStoreInt32:
- case MethodRecognizer::kFfiStoreInt64:
- case MethodRecognizer::kFfiStoreUint8:
- case MethodRecognizer::kFfiStoreUint16:
- case MethodRecognizer::kFfiStoreUint32:
- case MethodRecognizer::kFfiStoreUint64:
- case MethodRecognizer::kFfiStoreIntPtr:
- case MethodRecognizer::kFfiStoreFloat:
- case MethodRecognizer::kFfiStoreFloatUnaligned:
- case MethodRecognizer::kFfiStoreDouble:
- case MethodRecognizer::kFfiStoreDoubleUnaligned:
- case MethodRecognizer::kFfiStorePointer: {
+#define FFI_STORE(type) case MethodRecognizer::kFfiStore##type:
+ CLASS_LIST_FFI_NUMERIC(FFI_STORE)
+ FFI_STORE(FloatUnaligned)
+ FFI_STORE(DoubleUnaligned)
+ FFI_STORE(Pointer)
+#undef FFI_STORE
+ {
const classid_t ffi_type_arg_cid =
compiler::ffi::RecognizedMethodTypeArgCid(kind);
const AlignmentType alignment =
@@ -1549,6 +1519,45 @@
body += Constant(Bool::False());
#endif // defined(ARCH_IS_64_BIT)
} break;
+#define FFI_AS_EXTERNAL_TYPED_DATA(type) \
+ case MethodRecognizer::kFfiAsExternalTypedData##type:
+ CLASS_LIST_FFI_NUMERIC_FIXED_SIZE(FFI_AS_EXTERNAL_TYPED_DATA)
+#undef FFI_AS_EXTERNAL_TYPED_DATA
+ {
+ const classid_t ffi_type_arg_cid =
+ compiler::ffi::RecognizedMethodTypeArgCid(kind);
+ const classid_t external_typed_data_cid =
+ compiler::ffi::ElementExternalTypedDataCid(ffi_type_arg_cid);
+
+ auto class_table = thread_->isolate_group()->class_table();
+ ASSERT(class_table->HasValidClassAt(external_typed_data_cid));
+ const auto& typed_data_class = Class::ZoneHandle(
+ H.zone(), class_table->At(external_typed_data_cid));
+
+ // We assume that the caller has checked that the arguments are non-null
+ // and length is in the range [0, kSmiMax/elementSize].
+ ASSERT_EQUAL(function.NumParameters(), 2);
+ LocalVariable* arg_pointer = parsed_function_->RawParameterVariable(0);
+ LocalVariable* arg_length = parsed_function_->RawParameterVariable(1);
+
+ body += AllocateObject(TokenPosition::kNoSource, typed_data_class, 0);
+ LocalVariable* typed_data_object = MakeTemporary();
+
+ // Initialize the result's length field.
+ body += LoadLocal(typed_data_object);
+ body += LoadLocal(arg_length);
+ body += StoreNativeField(Slot::TypedDataBase_length(),
+ StoreInstanceFieldInstr::Kind::kInitializing,
+ kNoStoreBarrier);
+
+ // Initialize the result's data pointer field.
+ body += LoadLocal(typed_data_object);
+ body += LoadLocal(arg_pointer);
+ body += LoadNativeField(Slot::Pointer_data_field());
+ body += StoreNativeField(Slot::TypedDataBase_data_field(),
+ StoreInstanceFieldInstr::Kind::kInitializing,
+ kNoStoreBarrier);
+ } break;
case MethodRecognizer::kGetNativeField: {
auto& name = String::ZoneHandle(Z, function.name());
// Note: This method is force optimized so we can push untagged, etc.
diff --git a/runtime/vm/compiler/recognized_methods_list.h b/runtime/vm/compiler/recognized_methods_list.h
index 3ed3608..2d60271 100644
--- a/runtime/vm/compiler/recognized_methods_list.h
+++ b/runtime/vm/compiler/recognized_methods_list.h
@@ -221,6 +221,16 @@
V(::, _storePointer, FfiStorePointer, 0xea6b7751) \
V(::, _fromAddress, FfiFromAddress, 0xfd8cb1cc) \
V(Pointer, get:address, FfiGetAddress, 0x7cde87be) \
+ V(::, _asExternalTypedDataInt8, FfiAsExternalTypedDataInt8, 0x768a0698) \
+ V(::, _asExternalTypedDataInt16, FfiAsExternalTypedDataInt16, 0xd09cf9c6) \
+ V(::, _asExternalTypedDataInt32, FfiAsExternalTypedDataInt32, 0x38248946) \
+ V(::, _asExternalTypedDataInt64, FfiAsExternalTypedDataInt64, 0xafaa47fb) \
+ V(::, _asExternalTypedDataUint8, FfiAsExternalTypedDataUint8, 0x35228834) \
+ V(::, _asExternalTypedDataUint16, FfiAsExternalTypedDataUint16, 0x89a51e3a) \
+ V(::, _asExternalTypedDataUint32, FfiAsExternalTypedDataUint32, 0xd272dc41) \
+ V(::, _asExternalTypedDataUint64, FfiAsExternalTypedDataUint64, 0x06be71c5) \
+ V(::, _asExternalTypedDataFloat, FfiAsExternalTypedDataFloat, 0x6f465e0c) \
+ V(::, _asExternalTypedDataDouble, FfiAsExternalTypedDataDouble, 0x40cdd9e1) \
V(::, _getNativeField, GetNativeField, 0xa0139b85) \
V(::, reachabilityFence, ReachabilityFence, 0x619235c1) \
V(_Utf8Decoder, _scan, Utf8DecoderScan, 0x1dcaf73d) \
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 6fb03db..d1fe844 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -3177,8 +3177,8 @@
// run.
bool ForceOptimize() const {
return IsFfiFromAddress() || IsFfiGetAddress() || IsFfiLoad() ||
- IsFfiStore() || IsFfiTrampoline() || IsTypedDataViewFactory() ||
- IsUtf8Scan() || IsGetNativeField();
+ IsFfiStore() || IsFfiTrampoline() || IsFfiAsExternalTypedData() ||
+ IsTypedDataViewFactory() || IsUtf8Scan() || IsGetNativeField();
}
bool CanBeInlined() const;
@@ -3510,6 +3510,12 @@
return kind == MethodRecognizer::kFfiGetAddress;
}
+ bool IsFfiAsExternalTypedData() const {
+ const auto kind = recognized_kind();
+ return MethodRecognizer::kFfiAsExternalTypedDataInt8 <= kind &&
+ kind <= MethodRecognizer::kFfiAsExternalTypedDataDouble;
+ }
+
bool IsGetNativeField() const {
const auto kind = recognized_kind();
return kind == MethodRecognizer::kGetNativeField;
diff --git a/sdk/lib/_internal/vm/lib/ffi_patch.dart b/sdk/lib/_internal/vm/lib/ffi_patch.dart
index 2dcd5f8..8816c44 100644
--- a/sdk/lib/_internal/vm/lib/ffi_patch.dart
+++ b/sdk/lib/_internal/vm/lib/ffi_patch.dart
@@ -4,7 +4,7 @@
// All imports must be in all FFI patch files to not depend on the order
// the patches are applied.
-import "dart:_internal" show patch;
+import "dart:_internal" show patch, has63BitSmis;
import 'dart:typed_data';
import 'dart:isolate';
@@ -44,6 +44,29 @@
8, // windowsX64,
])[_abi()];
+@pragma("vm:prefer-inline")
+int get _smiMax {
+ // See runtime/vm/globals.h for how smiMax is calculated.
+ final smiBits = has63BitSmis ? 62 : 30;
+ return (1 << smiBits) - 1;
+}
+
+@pragma("vm:prefer-inline")
+void _checkExternalTypedDataLength(int length, int elementSize) {
+ final maxElements = _smiMax ~/ elementSize;
+ if (length < 0 || length > maxElements) {
+ throw ArgumentError("length must be in the range [0, $maxElements].");
+ }
+}
+
+@pragma("vm:prefer-inline")
+void _checkPointerAlignment(int address, int elementSize) {
+ if (address & (elementSize - 1) != 0) {
+ throw ArgumentError("Pointer address must be aligned to a multiple of "
+ "the element size ($elementSize).");
+ }
+}
+
@patch
int sizeOf<T extends NativeType>() {
// This case should have been rewritten in pre-processing.
@@ -62,8 +85,46 @@
external DS _asFunctionInternal<DS extends Function, NS extends Function>(
Pointer<NativeFunction<NS>> ptr, bool isLeaf);
-@pragma("vm:external-name", "Ffi_asExternalTypedData")
-external dynamic _asExternalTypedData(Pointer ptr, int count);
+@pragma("vm:recognized", "other")
+@pragma("vm:external-name", "Ffi_asExternalTypedDataInt8")
+external Int8List _asExternalTypedDataInt8(Pointer<Int8> ptr, int length);
+
+@pragma("vm:recognized", "other")
+@pragma("vm:external-name", "Ffi_asExternalTypedDataInt16")
+external Int16List _asExternalTypedDataInt16(Pointer<Int16> ptr, int length);
+
+@pragma("vm:recognized", "other")
+@pragma("vm:external-name", "Ffi_asExternalTypedDataInt32")
+external Int32List _asExternalTypedDataInt32(Pointer<Int32> ptr, int length);
+
+@pragma("vm:recognized", "other")
+@pragma("vm:external-name", "Ffi_asExternalTypedDataInt64")
+external Int64List _asExternalTypedDataInt64(Pointer<Int64> ptr, int length);
+
+@pragma("vm:recognized", "other")
+@pragma("vm:external-name", "Ffi_asExternalTypedDataUint8")
+external Uint8List _asExternalTypedDataUint8(Pointer<Uint8> ptr, int length);
+
+@pragma("vm:recognized", "other")
+@pragma("vm:external-name", "Ffi_asExternalTypedDataUint16")
+external Uint16List _asExternalTypedDataUint16(Pointer<Uint16> ptr, int length);
+
+@pragma("vm:recognized", "other")
+@pragma("vm:external-name", "Ffi_asExternalTypedDataUint32")
+external Uint32List _asExternalTypedDataUint32(Pointer<Uint32> ptr, int length);
+
+@pragma("vm:recognized", "other")
+@pragma("vm:external-name", "Ffi_asExternalTypedDataUint64")
+external Uint64List _asExternalTypedDataUint64(Pointer<Uint64> ptr, int length);
+
+@pragma("vm:recognized", "other")
+@pragma("vm:external-name", "Ffi_asExternalTypedDataFloat")
+external Float32List _asExternalTypedDataFloat(Pointer<Float> ptr, int length);
+
+@pragma("vm:recognized", "other")
+@pragma("vm:external-name", "Ffi_asExternalTypedDataDouble")
+external Float64List _asExternalTypedDataDouble(
+ Pointer<Double> ptr, int length);
// Returns a Function object for a native callback.
//
@@ -406,7 +467,13 @@
operator []=(int index, int value) => _storeInt8(this, index, value);
@patch
- Int8List asTypedList(int elements) => _asExternalTypedData(this, elements);
+ Int8List asTypedList(int length) {
+ ArgumentError.checkNotNull(this, "Pointer<Int8>");
+ ArgumentError.checkNotNull(length, "length");
+ _checkExternalTypedDataLength(length, 1);
+ _checkPointerAlignment(address, 1);
+ return _asExternalTypedDataInt8(this, length);
+ }
}
extension Int16Pointer on Pointer<Int16> {
@@ -423,7 +490,13 @@
operator []=(int index, int value) => _storeInt16(this, 2 * index, value);
@patch
- Int16List asTypedList(int elements) => _asExternalTypedData(this, elements);
+ Int16List asTypedList(int length) {
+ ArgumentError.checkNotNull(this, "Pointer<Int16>");
+ ArgumentError.checkNotNull(length, "length");
+ _checkExternalTypedDataLength(length, 2);
+ _checkPointerAlignment(address, 2);
+ return _asExternalTypedDataInt16(this, length);
+ }
}
extension Int32Pointer on Pointer<Int32> {
@@ -440,7 +513,13 @@
operator []=(int index, int value) => _storeInt32(this, 4 * index, value);
@patch
- Int32List asTypedList(int elements) => _asExternalTypedData(this, elements);
+ Int32List asTypedList(int length) {
+ ArgumentError.checkNotNull(this, "Pointer<Int32>");
+ ArgumentError.checkNotNull(length, "length");
+ _checkExternalTypedDataLength(length, 4);
+ _checkPointerAlignment(address, 4);
+ return _asExternalTypedDataInt32(this, length);
+ }
}
extension Int64Pointer on Pointer<Int64> {
@@ -457,7 +536,13 @@
operator []=(int index, int value) => _storeInt64(this, 8 * index, value);
@patch
- Int64List asTypedList(int elements) => _asExternalTypedData(this, elements);
+ Int64List asTypedList(int length) {
+ ArgumentError.checkNotNull(this, "Pointer<Int64>");
+ ArgumentError.checkNotNull(length, "length");
+ _checkExternalTypedDataLength(length, 8);
+ _checkPointerAlignment(address, 8);
+ return _asExternalTypedDataInt64(this, length);
+ }
}
extension Uint8Pointer on Pointer<Uint8> {
@@ -474,7 +559,13 @@
operator []=(int index, int value) => _storeUint8(this, index, value);
@patch
- Uint8List asTypedList(int elements) => _asExternalTypedData(this, elements);
+ Uint8List asTypedList(int length) {
+ ArgumentError.checkNotNull(this, "Pointer<Uint8>");
+ ArgumentError.checkNotNull(length, "length");
+ _checkExternalTypedDataLength(length, 1);
+ _checkPointerAlignment(address, 1);
+ return _asExternalTypedDataUint8(this, length);
+ }
}
extension Uint16Pointer on Pointer<Uint16> {
@@ -491,7 +582,13 @@
operator []=(int index, int value) => _storeUint16(this, 2 * index, value);
@patch
- Uint16List asTypedList(int elements) => _asExternalTypedData(this, elements);
+ Uint16List asTypedList(int length) {
+ ArgumentError.checkNotNull(this, "Pointer<Uint16>");
+ ArgumentError.checkNotNull(length, "length");
+ _checkExternalTypedDataLength(length, 2);
+ _checkPointerAlignment(address, 2);
+ return _asExternalTypedDataUint16(this, length);
+ }
}
extension Uint32Pointer on Pointer<Uint32> {
@@ -508,7 +605,13 @@
operator []=(int index, int value) => _storeUint32(this, 4 * index, value);
@patch
- Uint32List asTypedList(int elements) => _asExternalTypedData(this, elements);
+ Uint32List asTypedList(int length) {
+ ArgumentError.checkNotNull(this, "Pointer<Uint32>");
+ ArgumentError.checkNotNull(length, "length");
+ _checkExternalTypedDataLength(length, 4);
+ _checkPointerAlignment(address, 4);
+ return _asExternalTypedDataUint32(this, length);
+ }
}
extension Uint64Pointer on Pointer<Uint64> {
@@ -525,7 +628,13 @@
operator []=(int index, int value) => _storeUint64(this, 8 * index, value);
@patch
- Uint64List asTypedList(int elements) => _asExternalTypedData(this, elements);
+ Uint64List asTypedList(int length) {
+ ArgumentError.checkNotNull(this, "Pointer<Uint64>");
+ ArgumentError.checkNotNull(length, "length");
+ _checkExternalTypedDataLength(length, 8);
+ _checkPointerAlignment(address, 8);
+ return _asExternalTypedDataUint64(this, length);
+ }
}
extension IntPtrPointer on Pointer<IntPtr> {
@@ -557,7 +666,13 @@
operator []=(int index, double value) => _storeFloat(this, 4 * index, value);
@patch
- Float32List asTypedList(int elements) => _asExternalTypedData(this, elements);
+ Float32List asTypedList(int length) {
+ ArgumentError.checkNotNull(this, "Pointer<Float>");
+ ArgumentError.checkNotNull(length, "length");
+ _checkExternalTypedDataLength(length, 4);
+ _checkPointerAlignment(address, 4);
+ return _asExternalTypedDataFloat(this, length);
+ }
}
extension DoublePointer on Pointer<Double> {
@@ -574,7 +689,13 @@
operator []=(int index, double value) => _storeDouble(this, 8 * index, value);
@patch
- Float64List asTypedList(int elements) => _asExternalTypedData(this, elements);
+ Float64List asTypedList(int length) {
+ ArgumentError.checkNotNull(this, "Pointer<Double>");
+ ArgumentError.checkNotNull(length, "length");
+ _checkExternalTypedDataLength(length, 8);
+ _checkPointerAlignment(address, 8);
+ return _asExternalTypedDataDouble(this, length);
+ }
}
extension BoolPointer on Pointer<Bool> {
diff --git a/tools/VERSION b/tools/VERSION
index b55a51e..bde5370 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 16
PATCH 0
-PRERELEASE 57
+PRERELEASE 58
PRERELEASE_PATCH 0
\ No newline at end of file
diff --git a/tools/bots/try_benchmarks.sh b/tools/bots/try_benchmarks.sh
index d8ed384..2fb96f0 100755
--- a/tools/bots/try_benchmarks.sh
+++ b/tools/bots/try_benchmarks.sh
@@ -188,6 +188,8 @@
out/ReleaseIA32/dart --sound-null-safety benchmarks/NativeCall/dart/NativeCall.dart
out/ReleaseIA32/dart benchmarks/FfiBoringssl/dart2/FfiBoringssl.dart
out/ReleaseIA32/dart --sound-null-safety benchmarks/FfiBoringssl/dart/FfiBoringssl.dart
+ out/ReleaseIA32/dart benchmarks/FfiAsTypedList/dart2/FfiAsTypedList.dart
+ out/ReleaseIA32/dart --sound-null-safety benchmarks/FfiAsTypedList/dart/FfiAsTypedList.dart
out/ReleaseIA32/dart benchmarks/FfiCall/dart2/FfiCall.dart
out/ReleaseIA32/dart --sound-null-safety benchmarks/FfiCall/dart/FfiCall.dart
out/ReleaseIA32/dart benchmarks/FfiMemory/dart2/FfiMemory.dart