Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dart:ffi break up Pointer API into const/indexable/castable #35841

Closed
dcharkes opened this issue Feb 4, 2019 · 2 comments
Closed

dart:ffi break up Pointer API into const/indexable/castable #35841

dcharkes opened this issue Feb 4, 2019 · 2 comments
Labels
area-core-library SDK core library issues (core, async, ...); use area-vm or area-web for platform specific libraries. library-ffi type-design

Comments

@dcharkes
Copy link
Contributor

dcharkes commented Feb 4, 2019

Can we break up the Pointer API into multiple sub types?

do we need to have ConstPointer type that only supports loads?

Please do. Constness is a pretty useful abstraction when defining responsibilities in a C++ API; you can either require all APIs to be mutable (which is not elegant and will hamper interoperability), or ignore const in C++ APIs (which will not make anyone happy).

Note that you might have to figure out some way of expressing the relationship between const and non-const for composite objects (e.g. struct foo { int *a; int *b; } const foo c; means c.a is actually const as well.

  • store only if it is non-const

Could you structure these as subtypes with different supported operations? For many pointers (e.g. by default) you could support only load/store, and have subtypes for pointers that need to be cast-able or offset-able.

Most pointers in a well-defined API (e.g. SQLite) point to a singleton object, not to an array. The FFI can encode this (by e.g. having a subclass Span of Pointer; Pointer only supports load() and store().
Span also supports indexing...).

This will prevent accidentially using pointers that aren't meant to be offset from being used in an incorrect context.

You could also explore various representations for pointer-with-length; e.g. composite structures where the length is encoded in a different field in the same structure. You could transparently insert bounds check in the access.

  • elementAt() only if its indexable

Maybe use a different subtype of pointer to restrict pointer casting unless it's really necessary, especially for arbitrary pointers.

  • offsetBy and cast only if its castable

Related to: #35840

For reference, the current API without separate sub types:

/// Represents a pointer into the native C memory.
class Pointer<T extends NativeType> extends NativeType {
  const Pointer();

  /// Store a Dart value into this location.
  ///
  /// The [value] is automatically marshalled into its C representation.
  /// Note that ints which do not fit in [T] are truncated and sign extended,
  /// and doubles stored into Pointer<[Float]> lose precision.
  external void store(@DartRepresentationOf("T") Object value);

  /// Load a Dart value from this location.
  ///
  /// The value is automatically unmarshalled from its C representation.
  external R load<@DartRepresentationOf("T") R>();

  /// Access to the raw pointer value.
  external int get address;

  /// Pointer arithmetic (takes element size into account).
  external Pointer<T> elementAt(int index);

  /// Pointer arithmetic (byte offset).
  external Pointer<T> offsetBy(int offsetInBytes);

  /// Cast Pointer<T> to a (subtype of) Pointer<V>.
  external U cast<U extends Pointer>();

  /// Convert to Dart function, automatically marshalling the arguments
  /// and return value.
  ///
  /// Can only be called on [Pointer]<[NativeFunction]>.
  external R asFunction<@DartRepresentationOf("T") R extends Function>();

  /// Free memory on the C heap pointed to by this pointer with free().
  ///
  /// Note that this zeros out the address.
  external void free();

  /// Equality for Pointers only depends on their address.
  bool operator ==(other) {
    if (other == null) return false;
    return address == other.address;
  }

  /// The hash code for a Pointer only depends on its address.
  int get hashCode {
    return address.hashCode;
  }
}

/// Allocate [count] elements of type [T] on the C heap with malloc() and return
/// a pointer to the newly allocated memory.
///
/// Note that the memory are uninitialized.
external Pointer<T> allocate<T extends NativeType>({int count: 1});

/// Construction from raw value
external T fromAddress<T extends Pointer>(int ptr);

/// number of bytes used by native type T
external int sizeOf<T extends NativeType>();

/// Convert Dart function to a C function pointer, automatically marshalling
/// the arguments and return value
external Pointer<NativeFunction<T>> fromFunction<T extends Function>(
    @DartRepresentationOf("T") Function f);

/*
/// Return a pointer object that has a finalizer attached to it. When this
/// pointer object is collected by GC the given finalizer is invoked.
///
/// Note: the pointer object passed to the finalizer is not the same as
/// the pointer object that is returned from [finalizable] - it points
/// to the same memory region but has different identity.
external Pointer<T> finalizable<T extends NativeType>(
    Pointer<T> p, void finalizer(Pointer<T> ptr));
*/
@dcharkes dcharkes added the area-core-library SDK core library issues (core, async, ...); use area-vm or area-web for platform specific libraries. label Feb 4, 2019
@dcharkes
Copy link
Contributor Author

dcharkes commented Feb 5, 2019

And indexable could even be bounded indexable:

Maybe even consider slightly higher-level abstractions. For example, the array pointers in SQLite have a length field adjacent to the structure.

Would it be possible to encode that information (e.g. "the length is N bytes after the pointer itself" -- and copy out that information) in the type and check on every access?

@dcharkes
Copy link
Contributor Author

We have bounded indexable APIs:

At this point the dart:ffi API has been stable for a while, so I don't believe we would like to change it.

Closing as won't fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-core-library SDK core library issues (core, async, ...); use area-vm or area-web for platform specific libraries. library-ffi type-design
Projects
None yet
Development

No branches or pull requests

1 participant