[vm/ffi] Pointer load and store as extension methods

Issue: https://github.com/dart-lang/sdk/issues/37773
Change-Id: I836d6305b613cf05590d872874f4517831be3e08
Cq-Include-Trybots: luci.dart.try:vm-ffi-android-debug-arm-try,vm-ffi-android-debug-arm64-try,app-kernel-linux-debug-x64-try,vm-kernel-linux-debug-ia32-try,vm-dartkb-linux-debug-simarm64-try,vm-kernel-win-debug-x64-try,vm-kernel-win-debug-ia32-try,vm-dartkb-linux-debug-x64-try,vm-kernel-precomp-linux-debug-x64-try,vm-dartkb-linux-release-x64-abi-try,vm-kernel-precomp-android-release-arm64-try,vm-kernel-asan-linux-release-x64-try,vm-kernel-linux-release-simarm-try,vm-kernel-linux-release-simarm64-try,vm-kernel-mac-debug-simdbc64-try,vm-kernel-precomp-android-release-arm_x64-try,vm-kernel-reload-mac-release-simdbc64-try,vm-kernel-precomp-obfuscate-linux-release-x64-try,vm-kernel-reload-rollback-linux-debug-x64-try,vm-kernel-precomp-mac-release-simarm_x64-try
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/118992
Reviewed-by: Samir Jindel <sjindel@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
This commit is contained in:
Daco Harkes 2019-10-08 16:49:41 +00:00 committed by commit-bot@chromium.org
parent 17388522ea
commit 597cd06aec
10 changed files with 1578 additions and 25 deletions

View file

@ -364,6 +364,10 @@ class _FfiUseSiteTransformer extends FfiTransformer {
// this rewiring.
final DartType pointerType = node.receiver.getStaticType(env);
final DartType nativeType = _pointerTypeGetTypeArg(pointerType);
if (nativeType is TypeParameterType) {
// Do not rewire generic invocations.
return node;
}
final Class nativeClass = (nativeType as InterfaceType).classNode;
final NativeType nt = getType(nativeClass);
if (optimizedTypes.contains(nt)) {

View file

@ -50,15 +50,6 @@ static void CheckSized(const AbstractType& type_arg) {
// The following functions are runtime checks on arguments.
static const Pointer& AsPointer(const Instance& instance) {
if (!instance.IsPointer()) {
const String& error = String::Handle(String::NewFormatted(
"Expected a Pointer object but found %s", instance.ToCString()));
Exceptions::ThrowArgumentError(error);
}
return Pointer::Cast(instance);
}
static const Integer& AsInteger(const Instance& instance) {
if (!instance.IsInteger()) {
const String& error = String::Handle(String::NewFormatted(
@ -294,16 +285,10 @@ CLASS_LIST_FFI_NUMERIC(DEFINE_NATIVE_ENTRY_STORE)
DEFINE_NATIVE_ENTRY(Ffi_storePointer, 0, 2) {
GET_NON_NULL_NATIVE_ARGUMENT(Pointer, pointer, arguments->NativeArgAt(0));
GET_NATIVE_ARGUMENT(Instance, new_value, arguments->NativeArgAt(1));
GET_NON_NULL_NATIVE_ARGUMENT(Pointer, new_value, arguments->NativeArgAt(1));
AbstractType& pointer_type_arg =
AbstractType::Handle(pointer.type_argument());
if (new_value.IsNull()) {
const String& error = String::Handle(
String::NewFormatted("Argument to Pointer.store is null."));
Exceptions::ThrowArgumentError(error);
}
auto& new_value_type =
AbstractType::Handle(zone, new_value.GetType(Heap::kNew));
if (!new_value_type.IsSubtypeOf(pointer_type_arg, Heap::kNew)) {
@ -315,9 +300,8 @@ DEFINE_NATIVE_ENTRY(Ffi_storePointer, 0, 2) {
}
ASSERT(IsPointerType(pointer_type_arg));
ASSERT(new_value.IsPointer());
uword* slot = reinterpret_cast<uword*>(pointer.NativeAddress());
*slot = AsPointer(new_value).NativeAddress();
*slot = new_value.NativeAddress();
return Object::null();
}

View file

@ -0,0 +1,195 @@
// 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.
//
// This file generates the extension methods public API and the extension
// methods patch file for all integers, double, and float.
// The PointerPointer and PointerStruct extension are written by hand since
// those are not repetitive.
import 'dart:io';
//
// Configuration.
//
const Map<String, String> nativeToDartType = {
"Int8": "int",
"Int16": "int",
"Int32": "int",
"Int64": "int",
"Uint8": "int",
"Uint16": "int",
"Uint32": "int",
"Uint64": "int",
"IntPtr": "int",
"Float": "double",
"Double": "double",
};
//
// Generator.
//
main(List<String> arguments) {
final parsedArgs = parseArguments(arguments);
generate(parsedArgs.path, "ffi.g.dart", generatePublicExtension);
generate(parsedArgs.path, "ffi_patch.g.dart", generatePatchExtension);
}
void generate(Uri path, String fileName,
Function(StringBuffer, String, String) generator) {
final buffer = StringBuffer();
generateHeader(buffer);
nativeToDartType.forEach((String nativeType, String dartType) {
generator(buffer, nativeType, dartType);
});
generateFooter(buffer);
final fullPath = path.resolve(fileName).path;
new File(fullPath).writeAsStringSync(buffer.toString());
final fmtResult = Process.runSync(dartfmtPath().path, ["-w", fullPath]);
if (fmtResult.exitCode != 0) {
throw Exception(
"Formatting failed:\n${fmtResult.stdout}\n${fmtResult.stderr}\n");
}
print("Generated $fullPath.");
}
void generateHeader(StringBuffer buffer) {
final header = """
//
// The following code is generated, do not edit by hand.
//
// Code generated by `runtime/tools/ffi/sdk_lib_ffi_generator.dart`.
//
""";
buffer.write(header);
}
void generatePublicExtension(
StringBuffer buffer, String nativeType, String dartType) {
final storeTrunctateInt = """
/// Note that ints which do not fit in [$nativeType] are truncated.
""";
final storeTrunctateDouble = """
/// Note that doubles stored into Pointer<[Float]> lose precision.
""";
final storeTruncate =
isInt(nativeType) ? storeTrunctateInt : storeTrunctateDouble;
final loadSignExtendInt = """
/// Note that ints are signextended.
""";
final loadSignExtend = isInt(nativeType) ? loadSignExtendInt : "";
buffer.write("""
/// Extension on [Pointer] specialized for the type argument [$nativeType].
extension ${nativeType}Pointer on Pointer<$nativeType> {
/// Load a Dart value from this location.
///
/// The value is automatically unmarshalled from its native representation.
$loadSignExtend ///
/// Note that [address] needs to be aligned to the size of [$nativeType].
external $dartType get value;
/// Store a Dart value into this location.
///
/// The [value] is automatically marshalled into its native representation.
$storeTruncate ///
/// Note that [address] needs to be aligned to the size of [$nativeType].
external void set value($dartType value);
/// Load a Dart value from this location offset by [index].
///
/// The value is automatically unmarshalled from its native representation.
$loadSignExtend ///
/// Note that [address] needs to be aligned to the size of [$nativeType].
external $dartType operator [](int index);
/// Store a Dart value into this location offset by [index].
///
/// The [value] is automatically marshalled into its native representation.
$storeTruncate ///
/// Note that [address] needs to be aligned to the size of [$nativeType].
external void operator []=(int index, $dartType value);
}
""");
}
void generatePatchExtension(
StringBuffer buffer, String nativeType, String dartType) {
buffer.write("""
extension ${nativeType}Pointer on Pointer<$nativeType> {
@patch
$dartType get value => _load$nativeType(this);
@patch
void set value($dartType value) => _store$nativeType(this, value);
@patch
$dartType operator [](int index) => this.elementAt(index).value;
@patch
void operator []=(int index, $dartType value) => this.elementAt(index).value = value;
}
""");
}
void generateFooter(StringBuffer buffer) {
final footer = """
//
// End of generated code.
//
""";
buffer.write(footer);
}
//
// Helper functions.
//
bool isInt(String type) => type.startsWith("Int") || type.startsWith("Uint");
class Arguments {
final Uri path;
Arguments(this.path);
}
Arguments parseArguments(List<String> arguments) {
final parsedArgs = Map<String, dynamic>();
String flag = null;
for (final String arg in arguments) {
if (flag == "path") {
parsedArgs[flag] = Uri.parse(arg);
flag = null;
} else if (arg == "-p" || arg == "--path") {
flag = "path";
} else {
throw Exception("Unknown argument: $arg");
}
}
Uri path = parsedArgs["path"];
if (path == null) {
path = Platform.script;
print("No path provided, generating files next to generator.");
}
return Arguments(path);
}
Uri dartfmtPath() {
// TODO(dacoharkes): Use "../../../tools/sdks/dart-sdk/bin/dartfmt" when the
// pinned fully supports extension methods.
return Uri.parse("dartfmt");
}

View file

@ -1074,6 +1074,8 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfRecognizedMethod(
ASSERT(function.NumParameters() == 1);
body += LoadLocal(parsed_function_->RawParameterVariable(0)); // Pointer.
body += CheckNullOptimized(TokenPosition::kNoSource,
String::ZoneHandle(Z, function.name()));
body += LoadNativeField(Slot::Pointer_c_memory_address());
body += UnboxTruncate(kUnboxedIntPtr); // Truncating, so signed is ok.
body += ConvertIntptrToUntagged(); // Requires signed intptr.
@ -1169,6 +1171,8 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfRecognizedMethod(
// But we type check it as a method on a generic class at runtime.
body += LoadLocal(arg_value);
body += LoadLocal(arg_pointer);
body += CheckNullOptimized(TokenPosition::kNoSource,
String::ZoneHandle(Z, function.name()));
// We pass the Pointer type argument as instantiator_type_args.
//
// Call sites to this recognized method are guaranteed to pass a
@ -1189,6 +1193,8 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfRecognizedMethod(
ASSERT(function.NumParameters() == 2);
body += LoadLocal(arg_pointer); // Pointer.
body += CheckNullOptimized(TokenPosition::kNoSource,
String::ZoneHandle(Z, function.name()));
body += LoadNativeField(Slot::Pointer_c_memory_address());
body += UnboxTruncate(kUnboxedIntPtr); // Truncating, so signed is ok.
body += ConvertIntptrToUntagged(); // Requires signed intptr.

View file

@ -21494,7 +21494,6 @@ RawDynamicLibrary* DynamicLibrary::New(void* handle, Heap::Space space) {
}
bool Pointer::IsPointer(const Instance& obj) {
ASSERT(!obj.IsNull());
return RawObject::IsFfiPointerClassId(obj.raw()->GetClassId());
}

View file

@ -147,6 +147,8 @@ int _abi()
// allocating a Pointer with in elementAt/offsetBy. Allocating these pointers
// and GCing new spaces takes a lot of the benchmark time. The next speedup is
// getting rid of these allocations by inlining these functions.
//
// TODO(37773): Change _loadInt8 etc to take an index.
int _loadInt8(Pointer<Int8> pointer) native "Ffi_loadInt8";
int _loadInt16(Pointer<Int16> pointer) native "Ffi_loadInt16";
@ -236,3 +238,204 @@ Pointer<Double> _elementAtDouble(Pointer<Double> pointer, int index) =>
Pointer<Pointer<S>> _elementAtPointer<S extends NativeType>(
Pointer<Pointer<S>> pointer, int index) =>
Pointer.fromAddress(pointer.address + _intPtrSize * index);
//
// The following code is generated, do not edit by hand.
//
// Code generated by `runtime/tools/ffi/sdk_lib_ffi_generator.dart`.
//
extension Int8Pointer on Pointer<Int8> {
@patch
int get value => _loadInt8(this);
@patch
void set value(int value) => _storeInt8(this, value);
@patch
int operator [](int index) => this.elementAt(index).value;
@patch
void operator []=(int index, int value) =>
this.elementAt(index).value = value;
}
extension Int16Pointer on Pointer<Int16> {
@patch
int get value => _loadInt16(this);
@patch
void set value(int value) => _storeInt16(this, value);
@patch
int operator [](int index) => this.elementAt(index).value;
@patch
void operator []=(int index, int value) =>
this.elementAt(index).value = value;
}
extension Int32Pointer on Pointer<Int32> {
@patch
int get value => _loadInt32(this);
@patch
void set value(int value) => _storeInt32(this, value);
@patch
int operator [](int index) => this.elementAt(index).value;
@patch
void operator []=(int index, int value) =>
this.elementAt(index).value = value;
}
extension Int64Pointer on Pointer<Int64> {
@patch
int get value => _loadInt64(this);
@patch
void set value(int value) => _storeInt64(this, value);
@patch
int operator [](int index) => this.elementAt(index).value;
@patch
void operator []=(int index, int value) =>
this.elementAt(index).value = value;
}
extension Uint8Pointer on Pointer<Uint8> {
@patch
int get value => _loadUint8(this);
@patch
void set value(int value) => _storeUint8(this, value);
@patch
int operator [](int index) => this.elementAt(index).value;
@patch
void operator []=(int index, int value) =>
this.elementAt(index).value = value;
}
extension Uint16Pointer on Pointer<Uint16> {
@patch
int get value => _loadUint16(this);
@patch
void set value(int value) => _storeUint16(this, value);
@patch
int operator [](int index) => this.elementAt(index).value;
@patch
void operator []=(int index, int value) =>
this.elementAt(index).value = value;
}
extension Uint32Pointer on Pointer<Uint32> {
@patch
int get value => _loadUint32(this);
@patch
void set value(int value) => _storeUint32(this, value);
@patch
int operator [](int index) => this.elementAt(index).value;
@patch
void operator []=(int index, int value) =>
this.elementAt(index).value = value;
}
extension Uint64Pointer on Pointer<Uint64> {
@patch
int get value => _loadUint64(this);
@patch
void set value(int value) => _storeUint64(this, value);
@patch
int operator [](int index) => this.elementAt(index).value;
@patch
void operator []=(int index, int value) =>
this.elementAt(index).value = value;
}
extension IntPtrPointer on Pointer<IntPtr> {
@patch
int get value => _loadIntPtr(this);
@patch
void set value(int value) => _storeIntPtr(this, value);
@patch
int operator [](int index) => this.elementAt(index).value;
@patch
void operator []=(int index, int value) =>
this.elementAt(index).value = value;
}
extension FloatPointer on Pointer<Float> {
@patch
double get value => _loadFloat(this);
@patch
void set value(double value) => _storeFloat(this, value);
@patch
double operator [](int index) => this.elementAt(index).value;
@patch
void operator []=(int index, double value) =>
this.elementAt(index).value = value;
}
extension DoublePointer on Pointer<Double> {
@patch
double get value => _loadDouble(this);
@patch
void set value(double value) => _storeDouble(this, value);
@patch
double operator [](int index) => this.elementAt(index).value;
@patch
void operator []=(int index, double value) =>
this.elementAt(index).value = value;
}
//
// End of generated code.
//
extension PointerPointer<T extends NativeType> on Pointer<Pointer<T>> {
@patch
Pointer<T> get value => _loadPointer(this);
@patch
void set value(Pointer<T> value) => _storePointer(this, value);
@patch
Pointer<T> operator [](int index) => this.elementAt(index).value;
@patch
void operator []=(int index, Pointer<T> value) =>
this.elementAt(index).value = value;
}
extension StructPointer<T extends Struct> on Pointer<T> {
@patch
T get ref => _loadStruct(this);
@patch
T operator [](int index) {
Pointer<T> offsetPointer = this.elementAt(index);
return offsetPointer.ref;
}
}

View file

@ -63,11 +63,14 @@ class Pointer<T extends NativeType> extends NativeType {
/// Store a Dart value into this location.
///
/// The [value] is automatically marshalled into its native representation.
/// The `value` is automatically marshalled into its native representation.
/// Note that ints which do not fit in [T] are truncated and sign extended,
/// and doubles stored into Pointer<[Float]> lose precision.
///
/// Note that `address` needs to be aligned to the size of `T`.
/// Note that `this.address` needs to be aligned to the size of `T`.
///
/// Deprecated, use `pointer[...] =` and `pointer.value =` instead.
@deprecated
external void store(@DartRepresentationOf("T") Object value);
/// Load a Dart value from this location.
@ -76,7 +79,10 @@ class Pointer<T extends NativeType> extends NativeType {
/// Loading a [Struct] reference returns a reference backed by native memory
/// (the same pointer as it's loaded from).
///
/// Note that `address` needs to be aligned to the size of `T`.
/// Note that `this.address` needs to be aligned to the size of `T`.
///
/// Deprecated, use `pointer[...]` and `pointer.value` instead.
@deprecated
external R load<@DartRepresentationOf("T") R>();
/// Access to the raw pointer value.
@ -144,3 +150,436 @@ class Pointer<T extends NativeType> extends NativeType {
return address.hashCode;
}
}
//
// The following code is generated, do not edit by hand.
//
// Code generated by `runtime/tools/ffi/sdk_lib_ffi_generator.dart`.
//
/// Extension on [Pointer] specialized for the type argument [Int8].
extension Int8Pointer on Pointer<Int8> {
/// Load a Dart value from this location.
///
/// The value is automatically unmarshalled from its native representation.
/// Note that ints are signextended.
///
/// Note that [address] needs to be aligned to the size of [Int8].
external int get value;
/// Store a Dart value into this location.
///
/// The [value] is automatically marshalled into its native representation.
/// Note that ints which do not fit in [Int8] are truncated.
///
/// Note that [address] needs to be aligned to the size of [Int8].
external void set value(int value);
/// Load a Dart value from this location offset by [index].
///
/// The value is automatically unmarshalled from its native representation.
/// Note that ints are signextended.
///
/// Note that [address] needs to be aligned to the size of [Int8].
external int operator [](int index);
/// Store a Dart value into this location offset by [index].
///
/// The [value] is automatically marshalled into its native representation.
/// Note that ints which do not fit in [Int8] are truncated.
///
/// Note that [address] needs to be aligned to the size of [Int8].
external void operator []=(int index, int value);
}
/// Extension on [Pointer] specialized for the type argument [Int16].
extension Int16Pointer on Pointer<Int16> {
/// Load a Dart value from this location.
///
/// The value is automatically unmarshalled from its native representation.
/// Note that ints are signextended.
///
/// Note that [address] needs to be aligned to the size of [Int16].
external int get value;
/// Store a Dart value into this location.
///
/// The [value] is automatically marshalled into its native representation.
/// Note that ints which do not fit in [Int16] are truncated.
///
/// Note that [address] needs to be aligned to the size of [Int16].
external void set value(int value);
/// Load a Dart value from this location offset by [index].
///
/// The value is automatically unmarshalled from its native representation.
/// Note that ints are signextended.
///
/// Note that [address] needs to be aligned to the size of [Int16].
external int operator [](int index);
/// Store a Dart value into this location offset by [index].
///
/// The [value] is automatically marshalled into its native representation.
/// Note that ints which do not fit in [Int16] are truncated.
///
/// Note that [address] needs to be aligned to the size of [Int16].
external void operator []=(int index, int value);
}
/// Extension on [Pointer] specialized for the type argument [Int32].
extension Int32Pointer on Pointer<Int32> {
/// Load a Dart value from this location.
///
/// The value is automatically unmarshalled from its native representation.
/// Note that ints are signextended.
///
/// Note that [address] needs to be aligned to the size of [Int32].
external int get value;
/// Store a Dart value into this location.
///
/// The [value] is automatically marshalled into its native representation.
/// Note that ints which do not fit in [Int32] are truncated.
///
/// Note that [address] needs to be aligned to the size of [Int32].
external void set value(int value);
/// Load a Dart value from this location offset by [index].
///
/// The value is automatically unmarshalled from its native representation.
/// Note that ints are signextended.
///
/// Note that [address] needs to be aligned to the size of [Int32].
external int operator [](int index);
/// Store a Dart value into this location offset by [index].
///
/// The [value] is automatically marshalled into its native representation.
/// Note that ints which do not fit in [Int32] are truncated.
///
/// Note that [address] needs to be aligned to the size of [Int32].
external void operator []=(int index, int value);
}
/// Extension on [Pointer] specialized for the type argument [Int64].
extension Int64Pointer on Pointer<Int64> {
/// Load a Dart value from this location.
///
/// The value is automatically unmarshalled from its native representation.
/// Note that ints are signextended.
///
/// Note that [address] needs to be aligned to the size of [Int64].
external int get value;
/// Store a Dart value into this location.
///
/// The [value] is automatically marshalled into its native representation.
/// Note that ints which do not fit in [Int64] are truncated.
///
/// Note that [address] needs to be aligned to the size of [Int64].
external void set value(int value);
/// Load a Dart value from this location offset by [index].
///
/// The value is automatically unmarshalled from its native representation.
/// Note that ints are signextended.
///
/// Note that [address] needs to be aligned to the size of [Int64].
external int operator [](int index);
/// Store a Dart value into this location offset by [index].
///
/// The [value] is automatically marshalled into its native representation.
/// Note that ints which do not fit in [Int64] are truncated.
///
/// Note that [address] needs to be aligned to the size of [Int64].
external void operator []=(int index, int value);
}
/// Extension on [Pointer] specialized for the type argument [Uint8].
extension Uint8Pointer on Pointer<Uint8> {
/// Load a Dart value from this location.
///
/// The value is automatically unmarshalled from its native representation.
/// Note that ints are signextended.
///
/// Note that [address] needs to be aligned to the size of [Uint8].
external int get value;
/// Store a Dart value into this location.
///
/// The [value] is automatically marshalled into its native representation.
/// Note that ints which do not fit in [Uint8] are truncated.
///
/// Note that [address] needs to be aligned to the size of [Uint8].
external void set value(int value);
/// Load a Dart value from this location offset by [index].
///
/// The value is automatically unmarshalled from its native representation.
/// Note that ints are signextended.
///
/// Note that [address] needs to be aligned to the size of [Uint8].
external int operator [](int index);
/// Store a Dart value into this location offset by [index].
///
/// The [value] is automatically marshalled into its native representation.
/// Note that ints which do not fit in [Uint8] are truncated.
///
/// Note that [address] needs to be aligned to the size of [Uint8].
external void operator []=(int index, int value);
}
/// Extension on [Pointer] specialized for the type argument [Uint16].
extension Uint16Pointer on Pointer<Uint16> {
/// Load a Dart value from this location.
///
/// The value is automatically unmarshalled from its native representation.
/// Note that ints are signextended.
///
/// Note that [address] needs to be aligned to the size of [Uint16].
external int get value;
/// Store a Dart value into this location.
///
/// The [value] is automatically marshalled into its native representation.
/// Note that ints which do not fit in [Uint16] are truncated.
///
/// Note that [address] needs to be aligned to the size of [Uint16].
external void set value(int value);
/// Load a Dart value from this location offset by [index].
///
/// The value is automatically unmarshalled from its native representation.
/// Note that ints are signextended.
///
/// Note that [address] needs to be aligned to the size of [Uint16].
external int operator [](int index);
/// Store a Dart value into this location offset by [index].
///
/// The [value] is automatically marshalled into its native representation.
/// Note that ints which do not fit in [Uint16] are truncated.
///
/// Note that [address] needs to be aligned to the size of [Uint16].
external void operator []=(int index, int value);
}
/// Extension on [Pointer] specialized for the type argument [Uint32].
extension Uint32Pointer on Pointer<Uint32> {
/// Load a Dart value from this location.
///
/// The value is automatically unmarshalled from its native representation.
/// Note that ints are signextended.
///
/// Note that [address] needs to be aligned to the size of [Uint32].
external int get value;
/// Store a Dart value into this location.
///
/// The [value] is automatically marshalled into its native representation.
/// Note that ints which do not fit in [Uint32] are truncated.
///
/// Note that [address] needs to be aligned to the size of [Uint32].
external void set value(int value);
/// Load a Dart value from this location offset by [index].
///
/// The value is automatically unmarshalled from its native representation.
/// Note that ints are signextended.
///
/// Note that [address] needs to be aligned to the size of [Uint32].
external int operator [](int index);
/// Store a Dart value into this location offset by [index].
///
/// The [value] is automatically marshalled into its native representation.
/// Note that ints which do not fit in [Uint32] are truncated.
///
/// Note that [address] needs to be aligned to the size of [Uint32].
external void operator []=(int index, int value);
}
/// Extension on [Pointer] specialized for the type argument [Uint64].
extension Uint64Pointer on Pointer<Uint64> {
/// Load a Dart value from this location.
///
/// The value is automatically unmarshalled from its native representation.
/// Note that ints are signextended.
///
/// Note that [address] needs to be aligned to the size of [Uint64].
external int get value;
/// Store a Dart value into this location.
///
/// The [value] is automatically marshalled into its native representation.
/// Note that ints which do not fit in [Uint64] are truncated.
///
/// Note that [address] needs to be aligned to the size of [Uint64].
external void set value(int value);
/// Load a Dart value from this location offset by [index].
///
/// The value is automatically unmarshalled from its native representation.
/// Note that ints are signextended.
///
/// Note that [address] needs to be aligned to the size of [Uint64].
external int operator [](int index);
/// Store a Dart value into this location offset by [index].
///
/// The [value] is automatically marshalled into its native representation.
/// Note that ints which do not fit in [Uint64] are truncated.
///
/// Note that [address] needs to be aligned to the size of [Uint64].
external void operator []=(int index, int value);
}
/// Extension on [Pointer] specialized for the type argument [IntPtr].
extension IntPtrPointer on Pointer<IntPtr> {
/// Load a Dart value from this location.
///
/// The value is automatically unmarshalled from its native representation.
/// Note that ints are signextended.
///
/// Note that [address] needs to be aligned to the size of [IntPtr].
external int get value;
/// Store a Dart value into this location.
///
/// The [value] is automatically marshalled into its native representation.
/// Note that ints which do not fit in [IntPtr] are truncated.
///
/// Note that [address] needs to be aligned to the size of [IntPtr].
external void set value(int value);
/// Load a Dart value from this location offset by [index].
///
/// The value is automatically unmarshalled from its native representation.
/// Note that ints are signextended.
///
/// Note that [address] needs to be aligned to the size of [IntPtr].
external int operator [](int index);
/// Store a Dart value into this location offset by [index].
///
/// The [value] is automatically marshalled into its native representation.
/// Note that ints which do not fit in [IntPtr] are truncated.
///
/// Note that [address] needs to be aligned to the size of [IntPtr].
external void operator []=(int index, int value);
}
/// Extension on [Pointer] specialized for the type argument [Float].
extension FloatPointer on Pointer<Float> {
/// Load a Dart value from this location.
///
/// The value is automatically unmarshalled from its native representation.
///
/// Note that [address] needs to be aligned to the size of [Float].
external double get value;
/// Store a Dart value into this location.
///
/// The [value] is automatically marshalled into its native representation.
/// Note that doubles stored into Pointer<[Float]> lose precision.
///
/// Note that [address] needs to be aligned to the size of [Float].
external void set value(double value);
/// Load a Dart value from this location offset by [index].
///
/// The value is automatically unmarshalled from its native representation.
///
/// Note that [address] needs to be aligned to the size of [Float].
external double operator [](int index);
/// Store a Dart value into this location offset by [index].
///
/// The [value] is automatically marshalled into its native representation.
/// Note that doubles stored into Pointer<[Float]> lose precision.
///
/// Note that [address] needs to be aligned to the size of [Float].
external void operator []=(int index, double value);
}
/// Extension on [Pointer] specialized for the type argument [Double].
extension DoublePointer on Pointer<Double> {
/// Load a Dart value from this location.
///
/// The value is automatically unmarshalled from its native representation.
///
/// Note that [address] needs to be aligned to the size of [Double].
external double get value;
/// Store a Dart value into this location.
///
/// The [value] is automatically marshalled into its native representation.
/// Note that doubles stored into Pointer<[Float]> lose precision.
///
/// Note that [address] needs to be aligned to the size of [Double].
external void set value(double value);
/// Load a Dart value from this location offset by [index].
///
/// The value is automatically unmarshalled from its native representation.
///
/// Note that [address] needs to be aligned to the size of [Double].
external double operator [](int index);
/// Store a Dart value into this location offset by [index].
///
/// The [value] is automatically marshalled into its native representation.
/// Note that doubles stored into Pointer<[Float]> lose precision.
///
/// Note that [address] needs to be aligned to the size of [Double].
external void operator []=(int index, double value);
}
//
// End of generated code.
//
extension PointerPointer<T extends NativeType> on Pointer<Pointer<T>> {
/// Load a Dart value from this location.
///
/// The value is automatically unmarshalled from its native representation.
///
/// Note that [address] needs to be aligned to the size of [Pointer].
external Pointer<T> get value;
/// Store a Dart value into this location.
///
/// The [value] is automatically marshalled into its native representation.
///
/// Note that [address] needs to be aligned to the size of [Pointer].
external void set value(Pointer<T> value);
/// Load a Dart value from this location offset by [index].
///
/// The value is automatically unmarshalled from its native representation.
///
/// Note that [address] needs to be aligned to the size of [Pointer].
external Pointer<T> operator [](int index);
/// Store a Dart value into this location offset by [index].
///
/// The [value] is automatically marshalled into its native representation.
///
/// Note that [address] needs to be aligned to the size of [Pointer].
external void operator []=(int index, Pointer<T> value);
}
extension StructPointer<T extends Struct> on Pointer<T> {
/// Create a reference backed by native memory (the same pointer as it's loaded from).
///
/// Note that [address] needs to be aligned to the size of [T].
external T get ref;
/// Create a reference backed by native memory offset by [index].
///
/// Note that [address] needs to be aligned to the size of [T].
external T operator [](int index);
}

View file

@ -149,6 +149,8 @@ int _abi()
// allocating a Pointer with in elementAt/offsetBy. Allocating these pointers
// and GCing new spaces takes a lot of the benchmark time. The next speedup is
// getting rid of these allocations by inlining these functions.
//
// TODO(37773): Change _loadInt8 etc to take an index.
int _loadInt8(Pointer<Int8> pointer) native "Ffi_loadInt8";
int _loadInt16(Pointer<Int16> pointer) native "Ffi_loadInt16";
@ -238,3 +240,204 @@ Pointer<Double> _elementAtDouble(Pointer<Double> pointer, int index) =>
Pointer<Pointer<S>> _elementAtPointer<S extends NativeType>(
Pointer<Pointer<S>> pointer, int index) =>
Pointer.fromAddress(pointer.address + _intPtrSize * index);
//
// The following code is generated, do not edit by hand.
//
// Code generated by `runtime/tools/ffi/sdk_lib_ffi_generator.dart`.
//
extension Int8Pointer on Pointer<Int8> {
@patch
int get value => _loadInt8(this);
@patch
void set value(int value) => _storeInt8(this, value);
@patch
int operator [](int index) => this.elementAt(index).value;
@patch
void operator []=(int index, int value) =>
this.elementAt(index).value = value;
}
extension Int16Pointer on Pointer<Int16> {
@patch
int get value => _loadInt16(this);
@patch
void set value(int value) => _storeInt16(this, value);
@patch
int operator [](int index) => this.elementAt(index).value;
@patch
void operator []=(int index, int value) =>
this.elementAt(index).value = value;
}
extension Int32Pointer on Pointer<Int32> {
@patch
int get value => _loadInt32(this);
@patch
void set value(int value) => _storeInt32(this, value);
@patch
int operator [](int index) => this.elementAt(index).value;
@patch
void operator []=(int index, int value) =>
this.elementAt(index).value = value;
}
extension Int64Pointer on Pointer<Int64> {
@patch
int get value => _loadInt64(this);
@patch
void set value(int value) => _storeInt64(this, value);
@patch
int operator [](int index) => this.elementAt(index).value;
@patch
void operator []=(int index, int value) =>
this.elementAt(index).value = value;
}
extension Uint8Pointer on Pointer<Uint8> {
@patch
int get value => _loadUint8(this);
@patch
void set value(int value) => _storeUint8(this, value);
@patch
int operator [](int index) => this.elementAt(index).value;
@patch
void operator []=(int index, int value) =>
this.elementAt(index).value = value;
}
extension Uint16Pointer on Pointer<Uint16> {
@patch
int get value => _loadUint16(this);
@patch
void set value(int value) => _storeUint16(this, value);
@patch
int operator [](int index) => this.elementAt(index).value;
@patch
void operator []=(int index, int value) =>
this.elementAt(index).value = value;
}
extension Uint32Pointer on Pointer<Uint32> {
@patch
int get value => _loadUint32(this);
@patch
void set value(int value) => _storeUint32(this, value);
@patch
int operator [](int index) => this.elementAt(index).value;
@patch
void operator []=(int index, int value) =>
this.elementAt(index).value = value;
}
extension Uint64Pointer on Pointer<Uint64> {
@patch
int get value => _loadUint64(this);
@patch
void set value(int value) => _storeUint64(this, value);
@patch
int operator [](int index) => this.elementAt(index).value;
@patch
void operator []=(int index, int value) =>
this.elementAt(index).value = value;
}
extension IntPtrPointer on Pointer<IntPtr> {
@patch
int get value => _loadIntPtr(this);
@patch
void set value(int value) => _storeIntPtr(this, value);
@patch
int operator [](int index) => this.elementAt(index).value;
@patch
void operator []=(int index, int value) =>
this.elementAt(index).value = value;
}
extension FloatPointer on Pointer<Float> {
@patch
double get value => _loadFloat(this);
@patch
void set value(double value) => _storeFloat(this, value);
@patch
double operator [](int index) => this.elementAt(index).value;
@patch
void operator []=(int index, double value) =>
this.elementAt(index).value = value;
}
extension DoublePointer on Pointer<Double> {
@patch
double get value => _loadDouble(this);
@patch
void set value(double value) => _storeDouble(this, value);
@patch
double operator [](int index) => this.elementAt(index).value;
@patch
void operator []=(int index, double value) =>
this.elementAt(index).value = value;
}
//
// End of generated code.
//
extension PointerPointer<T extends NativeType> on Pointer<Pointer<T>> {
@patch
Pointer<T> get value => _loadPointer(this);
@patch
void set value(Pointer<T> value) => _storePointer(this, value);
@patch
Pointer<T> operator [](int index) => this.elementAt(index).value;
@patch
void operator []=(int index, Pointer<T> value) =>
this.elementAt(index).value = value;
}
extension StructPointer<T extends Struct> on Pointer<T> {
@patch
T get ref => _loadStruct(this);
@patch
T operator [](int index) {
Pointer<T> offsetPointer = this.elementAt(index);
return offsetPointer.ref;
}
}

View file

@ -65,11 +65,14 @@ class Pointer<T extends NativeType> extends NativeType {
/// Store a Dart value into this location.
///
/// The [value] is automatically marshalled into its native representation.
/// The `value` is automatically marshalled into its native representation.
/// Note that ints which do not fit in [T] are truncated and sign extended,
/// and doubles stored into Pointer<[Float]> lose precision.
///
/// Note that `address` needs to be aligned to the size of `T`.
/// Note that `this.address` needs to be aligned to the size of `T`.
///
/// Deprecated, use `pointer[...] =` and `pointer.value =` instead.
@deprecated
external void store(@DartRepresentationOf("T") Object value);
/// Load a Dart value from this location.
@ -78,7 +81,10 @@ class Pointer<T extends NativeType> extends NativeType {
/// Loading a [Struct] reference returns a reference backed by native memory
/// (the same pointer as it's loaded from).
///
/// Note that `address` needs to be aligned to the size of `T`.
/// Note that `this.address` needs to be aligned to the size of `T`.
///
/// Deprecated, use `pointer[...]` and `pointer.value` instead.
@deprecated
external R load<@DartRepresentationOf("T") R>();
/// Access to the raw pointer value.
@ -146,3 +152,436 @@ class Pointer<T extends NativeType> extends NativeType {
return address.hashCode;
}
}
//
// The following code is generated, do not edit by hand.
//
// Code generated by `runtime/tools/ffi/sdk_lib_ffi_generator.dart`.
//
/// Extension on [Pointer] specialized for the type argument [Int8].
extension Int8Pointer on Pointer<Int8> {
/// Load a Dart value from this location.
///
/// The value is automatically unmarshalled from its native representation.
/// Note that ints are signextended.
///
/// Note that [address] needs to be aligned to the size of [Int8].
external int get value;
/// Store a Dart value into this location.
///
/// The [value] is automatically marshalled into its native representation.
/// Note that ints which do not fit in [Int8] are truncated.
///
/// Note that [address] needs to be aligned to the size of [Int8].
external void set value(int value);
/// Load a Dart value from this location offset by [index].
///
/// The value is automatically unmarshalled from its native representation.
/// Note that ints are signextended.
///
/// Note that [address] needs to be aligned to the size of [Int8].
external int operator [](int index);
/// Store a Dart value into this location offset by [index].
///
/// The [value] is automatically marshalled into its native representation.
/// Note that ints which do not fit in [Int8] are truncated.
///
/// Note that [address] needs to be aligned to the size of [Int8].
external void operator []=(int index, int value);
}
/// Extension on [Pointer] specialized for the type argument [Int16].
extension Int16Pointer on Pointer<Int16> {
/// Load a Dart value from this location.
///
/// The value is automatically unmarshalled from its native representation.
/// Note that ints are signextended.
///
/// Note that [address] needs to be aligned to the size of [Int16].
external int get value;
/// Store a Dart value into this location.
///
/// The [value] is automatically marshalled into its native representation.
/// Note that ints which do not fit in [Int16] are truncated.
///
/// Note that [address] needs to be aligned to the size of [Int16].
external void set value(int value);
/// Load a Dart value from this location offset by [index].
///
/// The value is automatically unmarshalled from its native representation.
/// Note that ints are signextended.
///
/// Note that [address] needs to be aligned to the size of [Int16].
external int operator [](int index);
/// Store a Dart value into this location offset by [index].
///
/// The [value] is automatically marshalled into its native representation.
/// Note that ints which do not fit in [Int16] are truncated.
///
/// Note that [address] needs to be aligned to the size of [Int16].
external void operator []=(int index, int value);
}
/// Extension on [Pointer] specialized for the type argument [Int32].
extension Int32Pointer on Pointer<Int32> {
/// Load a Dart value from this location.
///
/// The value is automatically unmarshalled from its native representation.
/// Note that ints are signextended.
///
/// Note that [address] needs to be aligned to the size of [Int32].
external int get value;
/// Store a Dart value into this location.
///
/// The [value] is automatically marshalled into its native representation.
/// Note that ints which do not fit in [Int32] are truncated.
///
/// Note that [address] needs to be aligned to the size of [Int32].
external void set value(int value);
/// Load a Dart value from this location offset by [index].
///
/// The value is automatically unmarshalled from its native representation.
/// Note that ints are signextended.
///
/// Note that [address] needs to be aligned to the size of [Int32].
external int operator [](int index);
/// Store a Dart value into this location offset by [index].
///
/// The [value] is automatically marshalled into its native representation.
/// Note that ints which do not fit in [Int32] are truncated.
///
/// Note that [address] needs to be aligned to the size of [Int32].
external void operator []=(int index, int value);
}
/// Extension on [Pointer] specialized for the type argument [Int64].
extension Int64Pointer on Pointer<Int64> {
/// Load a Dart value from this location.
///
/// The value is automatically unmarshalled from its native representation.
/// Note that ints are signextended.
///
/// Note that [address] needs to be aligned to the size of [Int64].
external int get value;
/// Store a Dart value into this location.
///
/// The [value] is automatically marshalled into its native representation.
/// Note that ints which do not fit in [Int64] are truncated.
///
/// Note that [address] needs to be aligned to the size of [Int64].
external void set value(int value);
/// Load a Dart value from this location offset by [index].
///
/// The value is automatically unmarshalled from its native representation.
/// Note that ints are signextended.
///
/// Note that [address] needs to be aligned to the size of [Int64].
external int operator [](int index);
/// Store a Dart value into this location offset by [index].
///
/// The [value] is automatically marshalled into its native representation.
/// Note that ints which do not fit in [Int64] are truncated.
///
/// Note that [address] needs to be aligned to the size of [Int64].
external void operator []=(int index, int value);
}
/// Extension on [Pointer] specialized for the type argument [Uint8].
extension Uint8Pointer on Pointer<Uint8> {
/// Load a Dart value from this location.
///
/// The value is automatically unmarshalled from its native representation.
/// Note that ints are signextended.
///
/// Note that [address] needs to be aligned to the size of [Uint8].
external int get value;
/// Store a Dart value into this location.
///
/// The [value] is automatically marshalled into its native representation.
/// Note that ints which do not fit in [Uint8] are truncated.
///
/// Note that [address] needs to be aligned to the size of [Uint8].
external void set value(int value);
/// Load a Dart value from this location offset by [index].
///
/// The value is automatically unmarshalled from its native representation.
/// Note that ints are signextended.
///
/// Note that [address] needs to be aligned to the size of [Uint8].
external int operator [](int index);
/// Store a Dart value into this location offset by [index].
///
/// The [value] is automatically marshalled into its native representation.
/// Note that ints which do not fit in [Uint8] are truncated.
///
/// Note that [address] needs to be aligned to the size of [Uint8].
external void operator []=(int index, int value);
}
/// Extension on [Pointer] specialized for the type argument [Uint16].
extension Uint16Pointer on Pointer<Uint16> {
/// Load a Dart value from this location.
///
/// The value is automatically unmarshalled from its native representation.
/// Note that ints are signextended.
///
/// Note that [address] needs to be aligned to the size of [Uint16].
external int get value;
/// Store a Dart value into this location.
///
/// The [value] is automatically marshalled into its native representation.
/// Note that ints which do not fit in [Uint16] are truncated.
///
/// Note that [address] needs to be aligned to the size of [Uint16].
external void set value(int value);
/// Load a Dart value from this location offset by [index].
///
/// The value is automatically unmarshalled from its native representation.
/// Note that ints are signextended.
///
/// Note that [address] needs to be aligned to the size of [Uint16].
external int operator [](int index);
/// Store a Dart value into this location offset by [index].
///
/// The [value] is automatically marshalled into its native representation.
/// Note that ints which do not fit in [Uint16] are truncated.
///
/// Note that [address] needs to be aligned to the size of [Uint16].
external void operator []=(int index, int value);
}
/// Extension on [Pointer] specialized for the type argument [Uint32].
extension Uint32Pointer on Pointer<Uint32> {
/// Load a Dart value from this location.
///
/// The value is automatically unmarshalled from its native representation.
/// Note that ints are signextended.
///
/// Note that [address] needs to be aligned to the size of [Uint32].
external int get value;
/// Store a Dart value into this location.
///
/// The [value] is automatically marshalled into its native representation.
/// Note that ints which do not fit in [Uint32] are truncated.
///
/// Note that [address] needs to be aligned to the size of [Uint32].
external void set value(int value);
/// Load a Dart value from this location offset by [index].
///
/// The value is automatically unmarshalled from its native representation.
/// Note that ints are signextended.
///
/// Note that [address] needs to be aligned to the size of [Uint32].
external int operator [](int index);
/// Store a Dart value into this location offset by [index].
///
/// The [value] is automatically marshalled into its native representation.
/// Note that ints which do not fit in [Uint32] are truncated.
///
/// Note that [address] needs to be aligned to the size of [Uint32].
external void operator []=(int index, int value);
}
/// Extension on [Pointer] specialized for the type argument [Uint64].
extension Uint64Pointer on Pointer<Uint64> {
/// Load a Dart value from this location.
///
/// The value is automatically unmarshalled from its native representation.
/// Note that ints are signextended.
///
/// Note that [address] needs to be aligned to the size of [Uint64].
external int get value;
/// Store a Dart value into this location.
///
/// The [value] is automatically marshalled into its native representation.
/// Note that ints which do not fit in [Uint64] are truncated.
///
/// Note that [address] needs to be aligned to the size of [Uint64].
external void set value(int value);
/// Load a Dart value from this location offset by [index].
///
/// The value is automatically unmarshalled from its native representation.
/// Note that ints are signextended.
///
/// Note that [address] needs to be aligned to the size of [Uint64].
external int operator [](int index);
/// Store a Dart value into this location offset by [index].
///
/// The [value] is automatically marshalled into its native representation.
/// Note that ints which do not fit in [Uint64] are truncated.
///
/// Note that [address] needs to be aligned to the size of [Uint64].
external void operator []=(int index, int value);
}
/// Extension on [Pointer] specialized for the type argument [IntPtr].
extension IntPtrPointer on Pointer<IntPtr> {
/// Load a Dart value from this location.
///
/// The value is automatically unmarshalled from its native representation.
/// Note that ints are signextended.
///
/// Note that [address] needs to be aligned to the size of [IntPtr].
external int get value;
/// Store a Dart value into this location.
///
/// The [value] is automatically marshalled into its native representation.
/// Note that ints which do not fit in [IntPtr] are truncated.
///
/// Note that [address] needs to be aligned to the size of [IntPtr].
external void set value(int value);
/// Load a Dart value from this location offset by [index].
///
/// The value is automatically unmarshalled from its native representation.
/// Note that ints are signextended.
///
/// Note that [address] needs to be aligned to the size of [IntPtr].
external int operator [](int index);
/// Store a Dart value into this location offset by [index].
///
/// The [value] is automatically marshalled into its native representation.
/// Note that ints which do not fit in [IntPtr] are truncated.
///
/// Note that [address] needs to be aligned to the size of [IntPtr].
external void operator []=(int index, int value);
}
/// Extension on [Pointer] specialized for the type argument [Float].
extension FloatPointer on Pointer<Float> {
/// Load a Dart value from this location.
///
/// The value is automatically unmarshalled from its native representation.
///
/// Note that [address] needs to be aligned to the size of [Float].
external double get value;
/// Store a Dart value into this location.
///
/// The [value] is automatically marshalled into its native representation.
/// Note that doubles stored into Pointer<[Float]> lose precision.
///
/// Note that [address] needs to be aligned to the size of [Float].
external void set value(double value);
/// Load a Dart value from this location offset by [index].
///
/// The value is automatically unmarshalled from its native representation.
///
/// Note that [address] needs to be aligned to the size of [Float].
external double operator [](int index);
/// Store a Dart value into this location offset by [index].
///
/// The [value] is automatically marshalled into its native representation.
/// Note that doubles stored into Pointer<[Float]> lose precision.
///
/// Note that [address] needs to be aligned to the size of [Float].
external void operator []=(int index, double value);
}
/// Extension on [Pointer] specialized for the type argument [Double].
extension DoublePointer on Pointer<Double> {
/// Load a Dart value from this location.
///
/// The value is automatically unmarshalled from its native representation.
///
/// Note that [address] needs to be aligned to the size of [Double].
external double get value;
/// Store a Dart value into this location.
///
/// The [value] is automatically marshalled into its native representation.
/// Note that doubles stored into Pointer<[Float]> lose precision.
///
/// Note that [address] needs to be aligned to the size of [Double].
external void set value(double value);
/// Load a Dart value from this location offset by [index].
///
/// The value is automatically unmarshalled from its native representation.
///
/// Note that [address] needs to be aligned to the size of [Double].
external double operator [](int index);
/// Store a Dart value into this location offset by [index].
///
/// The [value] is automatically marshalled into its native representation.
/// Note that doubles stored into Pointer<[Float]> lose precision.
///
/// Note that [address] needs to be aligned to the size of [Double].
external void operator []=(int index, double value);
}
//
// End of generated code.
//
extension PointerPointer<T extends NativeType> on Pointer<Pointer<T>> {
/// Load a Dart value from this location.
///
/// The value is automatically unmarshalled from its native representation.
///
/// Note that [address] needs to be aligned to the size of [Pointer].
external Pointer<T> get value;
/// Store a Dart value into this location.
///
/// The [value] is automatically marshalled into its native representation.
///
/// Note that [address] needs to be aligned to the size of [Pointer].
external void set value(Pointer<T> value);
/// Load a Dart value from this location offset by [index].
///
/// The value is automatically unmarshalled from its native representation.
///
/// Note that [address] needs to be aligned to the size of [Pointer].
external Pointer<T> operator [](int index);
/// Store a Dart value into this location offset by [index].
///
/// The [value] is automatically marshalled into its native representation.
///
/// Note that [address] needs to be aligned to the size of [Pointer].
external void operator []=(int index, Pointer<T> value);
}
extension StructPointer<T extends Struct> on Pointer<T> {
/// Create a reference backed by native memory (the same pointer as it's loaded from).
///
/// Note that [address] needs to be aligned to the size of [T].
external T get ref;
/// Create a reference backed by native memory offset by [index].
///
/// Note that [address] needs to be aligned to the size of [T].
external T operator [](int index);
}

View file

@ -0,0 +1,81 @@
// 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.
import 'dart:ffi';
import "package:expect/expect.dart";
main(List<String> arguments) {
for (int i = 0; i < 100; i++) {
testStoreLoad();
testNullReceivers();
testNullArguments();
testReifiedGeneric();
}
}
testStoreLoad() {
final p = Pointer<Int8>.allocate(count: 2);
p.value = 10;
Expect.equals(10, p.value);
p[1] = 20;
Expect.equals(20, p[1]);
final p1 = Pointer<Double>.allocate(count: 2);
p1.value = 10.0;
Expect.approxEquals(10.0, p1.value);
p1[1] = 20.0;
Expect.approxEquals(20.0, p1[1]);
p1.free();
final p2 = Pointer<Pointer<Int8>>.allocate(count: 2);
p2.value = p;
Expect.equals(p, p2.value);
p2[1] = p;
Expect.equals(p, p2[1]);
p2.free();
p.free();
final p3 = Pointer<Foo>.allocate();
Foo foo = p3.ref;
foo.a = 1;
Expect.equals(1, foo.a);
p3.free();
}
/// With extension methods, the receiver position can be null.
testNullReceivers() {
Pointer<Int8> p = Pointer.allocate();
Pointer<Int8> p4 = null;
Expect.throws(() => Expect.equals(10, p4.value));
Expect.throws(() => p4.value = 10);
Pointer<Pointer<Int8>> p5 = null;
Expect.throws(() => Expect.equals(10, p5.value));
Expect.throws(() => p5.value = p);
Pointer<Foo> p6 = null;
Expect.throws(() => Expect.equals(10, p6.ref));
p.free();
}
testNullArguments() {
Pointer<Int8> p = Pointer.allocate();
Expect.throws(() => p.value = null);
p.free();
}
testReifiedGeneric() {
final p = Pointer<Pointer<Int8>>.allocate();
Pointer<Pointer<NativeType>> p2 = p;
Expect.isTrue(p2.value is Pointer<Int8>);
p.free();
}
class Foo extends Struct<Foo> {
@Int8()
int a;
}