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

[RFC FS-1109] Additional intrinsics for the NativePtr module #11682

Merged
merged 19 commits into from
Jul 13, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 44 additions & 13 deletions src/fsharp/FSharp.Core/nativeptr.fs
Original file line number Diff line number Diff line change
Expand Up @@ -16,47 +16,78 @@ open System.Runtime.InteropServices
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module NativePtr =


[<NoDynamicInvocation>]
[<CompiledName("OfNativeIntInlined")>]
let inline ofNativeInt (address:nativeint) = (# "" address : nativeptr<'T> #)
let inline ofNativeInt (address: nativeint) = (# "" address : nativeptr<'T> #)

[<NoDynamicInvocation>]
[<CompiledName("ToNativeIntInlined")>]
let inline toNativeInt (address: nativeptr<'T>) = (# "" address : nativeint #)
let inline toNativeInt (address: nativeptr<'T>) = (# "" address : nativeint #)

[<NoDynamicInvocation>]
[<CompiledName("OfVoidPtrInlined")>]
let inline ofVoidPtr (address: voidptr) = (# "" address : nativeptr<'T> #)

[<NoDynamicInvocation>]
[<CompiledName("ToVoidPtrInlined")>]
let inline toVoidPtr (address: nativeptr<'T>) = (# "" address : voidptr #)

[<NoDynamicInvocation>]
[<CompiledName("OfVoidPtrInlined")>]
let inline ofVoidPtr (address: voidptr) = (# "" address : nativeptr<'T> #)
[<CompiledName("OfILSigPtrInlined")>]
let inline ofILSigPtr (address: ilsigptr<'T>) = (# "" address : nativeptr<'T> #)

[<NoDynamicInvocation>]
[<CompiledName("ToILSigPtrInlined")>]
let inline toILSigPtr (address: nativeptr<'T>) = (# "" address : ilsigptr<'T> #)

[<NoDynamicInvocation>]
[<CompiledName("ToByRefInlined")>]
let inline toByRef (address: nativeptr<'T>) : byref<'T> = (# "" address : 'T byref #)

[<NoDynamicInvocation>]
[<CompiledName("AddPointerInlined")>]
let inline add (address : nativeptr<'T>) (index:int) : nativeptr<'T> = toNativeInt address + nativeint index * (# "sizeof !0" type('T) : nativeint #) |> ofNativeInt
let inline add (address: nativeptr<'T>) (index: int) : nativeptr<'T> = toNativeInt address + nativeint index * (# "sizeof !0" type('T) : nativeint #) |> ofNativeInt

[<NoDynamicInvocation>]
[<CompiledName("GetPointerInlined")>]
let inline get (address : nativeptr<'T>) index = (# "ldobj !0" type ('T) (add address index) : 'T #)
let inline get (address: nativeptr<'T>) index = (# "ldobj !0" type('T) (add address index) : 'T #)

[<NoDynamicInvocation>]
[<CompiledName("SetPointerInlined")>]
let inline set (address : nativeptr<'T>) index (value : 'T) = (# "stobj !0" type ('T) (add address index) value #)
let inline set (address: nativeptr<'T>) index (value: 'T) = (# "stobj !0" type('T) (add address index) value #)

[<NoDynamicInvocation>]
[<CompiledName("ReadPointerInlined")>]
let inline read (address : nativeptr<'T>) = (# "ldobj !0" type ('T) address : 'T #)
let inline read (address: nativeptr<'T>) = (# "ldobj !0" type('T) address : 'T #)

[<NoDynamicInvocation>]
[<CompiledName("WritePointerInlined")>]
let inline write (address : nativeptr<'T>) (value : 'T) = (# "stobj !0" type ('T) address value #)
let inline write (address: nativeptr<'T>) (value : 'T) = (# "stobj !0" type('T) address value #)

[<NoDynamicInvocation>]
[<CompiledName("StackAllocate")>]
let inline stackalloc (count:int) : nativeptr<'T> = (# "localloc" (count * sizeof<'T>) : nativeptr<'T> #)
let inline stackalloc (count: int) : nativeptr<'T> = (# "localloc" (count * sizeof<'T>) : nativeptr<'T> #)

[<NoDynamicInvocation>]
[<CompiledName("NullPointer")>]
let inline nullPtr<'T when 'T : unmanaged> : nativeptr<'T> = (# "ldnull" : nativeptr<'T> #)

[<NoDynamicInvocation>]
[<CompiledName("IsNullPointer")>]
let inline isNullPtr (address: nativeptr<'T>) = (# "ceq" nullPtr<'T> address : bool #)

[<NoDynamicInvocation>]
[<CompiledName("ClearPointerInlined")>]
let inline clear (address: nativeptr<'T>) = (# "initobj !0" type('T) address #)

[<NoDynamicInvocation>]
[<CompiledName("ToByRefInlined")>]
let inline toByRef (address: nativeptr<'T>) : byref<'T> = (# "" address : 'T byref #)
[<CompiledName("InitializeBlockInlined")>]
let inline initBlock (address: nativeptr<'T>) (value: byte) (count: uint32) = (# "initblk" address value count #)

[<NoDynamicInvocation>]
[<CompiledName("CopyPointerInlined")>]
let inline copy (destination: nativeptr<'T>) (source: nativeptr<'T>) = (# "cpobj !0" type('T) destination source #)

[<NoDynamicInvocation>]
[<CompiledName("CopyBlockInlined")>]
let inline copyBlock (destination: nativeptr<'T>) (source: nativeptr<'T>) (count: int) = (# "cpblk" destination source (count * sizeof<'T>) #)
118 changes: 93 additions & 25 deletions src/fsharp/FSharp.Core/nativeptr.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -20,38 +20,65 @@ namespace Microsoft.FSharp.NativeInterop
[<Unverifiable>]
[<CompiledName("OfNativeIntInlined")>]
/// <summary>Returns a typed native pointer for a given machine address.</summary>
/// <param name="address">The pointer address.</param>
///
/// <returns>A typed pointer.</returns>
val inline ofNativeInt : address:nativeint -> nativeptr<'T>
/// <param name="address">The machine address.</param>
///
/// <returns>A typed native pointer.</returns>
val inline ofNativeInt : address: nativeint -> nativeptr<'T>

[<Unverifiable>]
[<CompiledName("ToVoidPtrInlined")>]
/// <summary>Returns an untyped native pointer for a given typed pointer.</summary>
[<CompiledName("ToNativeIntInlined")>]
/// <summary>Returns a machine address for a given typed native pointer.</summary>
///
/// <param name="address">The pointer address.</param>
/// <param name="address">The typed native pointer.</param>
///
/// <returns>A typed pointer.</returns>
val inline toVoidPtr : address:nativeptr<'T> -> voidptr
/// <returns>The machine address.</returns>
val inline toNativeInt : address: nativeptr<'T> -> nativeint

[<Unverifiable>]
[<CompiledName("OfVoidPtrInlined")>]
/// <summary>Returns a typed native pointer for a untyped native pointer.</summary>
///
/// <param name="address">The untyped pointer.</param>
/// <param name="address">The untyped native pointer.</param>
///
/// <returns>A typed pointer.</returns>
/// <returns>A typed native pointer.</returns>
val inline ofVoidPtr : address: voidptr -> nativeptr<'T>

[<Unverifiable>]
[<CompiledName("ToNativeIntInlined")>]
/// <summary>Returns a machine address for a given typed native pointer.</summary>
[<CompiledName("ToVoidPtrInlined")>]
/// <summary>Returns an untyped native pointer for a given typed native pointer.</summary>
///
/// <param name="address">The input pointer.</param>
/// <param name="address">The typed native pointer.</param>
///
/// <returns>The machine address.</returns>
val inline toNativeInt : address:nativeptr<'T> -> nativeint
/// <returns>An untyped native pointer.</returns>
val inline toVoidPtr : address: nativeptr<'T> -> voidptr

[<Unverifiable>]
[<CompiledName("OfILSigPtrInlined")>]
/// <summary>Returns a typed native pointer for a Common IL (Intermediate Language) signature pointer.</summary>
///
/// <param name="address">The Common IL signature pointer.</param>
///
/// <returns>A typed native pointer.</returns>
val inline ofILSigPtr : address: ilsigptr<'T> -> nativeptr<'T>

[<Unverifiable>]
[<CompiledName("ToILSigPtrInlined")>]
/// <summary>Returns a Common IL (Intermediate Language) signature pointer for a given typed native pointer.</summary>
///
/// <param name="address">The typed native pointer.</param>
///
/// <returns>A Common IL signature pointer.</returns>
val inline toILSigPtr : address: nativeptr<'T> -> ilsigptr<'T>

/// <summary>Converts a given typed native pointer to a managed pointer.</summary>
///
/// <param name="address">The typed native pointer.</param>
///
/// <returns>The managed pointer.</returns>
[<Unverifiable>]
[<CompiledName("ToByRefInlined")>]
val inline toByRef: address: nativeptr<'T> -> byref<'T>

[<Unverifiable>]
[<CompiledName("AddPointerInlined")>]
Expand All @@ -62,7 +89,7 @@ namespace Microsoft.FSharp.NativeInterop
/// <param name="index">The index by which to offset the pointer.</param>
///
/// <returns>A typed pointer.</returns>
val inline add : address:nativeptr<'T> -> index:int -> nativeptr<'T>
val inline add : address: nativeptr<'T> -> index: int -> nativeptr<'T>

[<Unverifiable>]
[<CompiledName("GetPointerInlined")>]
Expand All @@ -73,7 +100,7 @@ namespace Microsoft.FSharp.NativeInterop
/// <param name="index">The index by which to offset the pointer.</param>
///
/// <returns>The value at the pointer address.</returns>
val inline get : address:nativeptr<'T> -> index:int -> 'T
val inline get : address: nativeptr<'T> -> index: int -> 'T

[<Unverifiable>]
[<CompiledName("ReadPointerInlined")>]
Expand All @@ -82,15 +109,15 @@ namespace Microsoft.FSharp.NativeInterop
/// <param name="address">The input pointer.</param>
///
/// <returns>The value at the pointer address.</returns>
val inline read : address:nativeptr<'T> -> 'T
val inline read : address: nativeptr<'T> -> 'T

[<Unverifiable>]
[<CompiledName("WritePointerInlined")>]
/// <summary>Assigns the <c>value</c> into the memory location referenced by the given typed native pointer.</summary>
///
/// <param name="address">The input pointer.</param>
/// <param name="value">The value to assign.</param>
val inline write : address:nativeptr<'T> -> value:'T -> unit
val inline write : address: nativeptr<'T> -> value: 'T -> unit

[<Unverifiable>]
[<CompiledName("SetPointerInlined")>]
Expand All @@ -100,7 +127,7 @@ namespace Microsoft.FSharp.NativeInterop
/// <param name="address">The input pointer.</param>
/// <param name="index">The index by which to offset the pointer.</param>
/// <param name="value">The value to assign.</param>
val inline set : address:nativeptr<'T> -> index:int -> value:'T -> unit
val inline set : address: nativeptr<'T> -> index: int -> value: 'T -> unit

/// <summary>Allocates a region of memory on the stack.</summary>
///
Expand All @@ -109,13 +136,54 @@ namespace Microsoft.FSharp.NativeInterop
/// <returns>A typed pointer to the allocated memory.</returns>
[<Unverifiable>]
[<CompiledName("StackAllocate")>]
val inline stackalloc: count:int -> nativeptr<'T>
val inline stackalloc: count: int -> nativeptr<'T>

/// <summary>Gets the null native pointer.</summary>
///
/// <returns>The null native pointer.</returns>
[<Unverifiable>]
[<GeneralizableValue>]
[<CompiledName("NullPointer")>]
val inline nullPtr<'T when 'T : unmanaged> : nativeptr<'T>

/// <summary>Tests whether the given native pointer is null.</summary>
///
/// <param name="address">The input pointer.</param>
///
/// <returns>Whether the given native pointer is null.</returns>
[<Unverifiable>]
[<CompiledName("IsNullPointer")>]
val inline isNullPtr: address: nativeptr<'T> -> bool

[<Unverifiable>]
[<CompiledName("ClearPointerInlined")>]
/// <summary>Clears the value stored at the location of a given native pointer.</summary>
///
/// <param name="address">The input pointer.</param>
val inline clear : address: nativeptr<'T> -> unit

/// <summary>Converts a given typed native pointer to a managed pointer.</summary>
[<Unverifiable>]
[<CompiledName("InitializeBlockInlined")>]
/// <summary>Initializes a specified block of memory starting at a specific address to a given byte count and initial byte value.</summary>
///
/// <param name="address">The input pointer.</param>
/// <param name="value">The initial byte value.</param>
/// <param name="count">The total repeat count of the byte value.</param>
val inline initBlock : address: nativeptr<'T> -> value: byte -> count: uint32 -> unit

[<Unverifiable>]
[<CompiledName("CopyPointerInlined")>]
/// <summary>Copies a value to a specified destination address from a specified source address.</summary>
///
/// <returns>The managed pointer.</returns>
/// <param name="destination">The destination pointer.</param>
/// <param name="source">The source pointer.</param>
val inline copy : destination: nativeptr<'T> -> source: nativeptr<'T> -> unit

[<Unverifiable>]
[<CompiledName("ToByRefInlined")>]
val inline toByRef: address: nativeptr<'T> -> byref<'T>
[<CompiledName("CopyBlockInlined")>]
/// <summary>Copies a block of memory to a specified destination address starting from a specified source address until a specified byte count of (count * sizeof&lt;'T&gt;).</summary>
///
/// <param name="destination">The destination pointer.</param>
/// <param name="source">The source pointer.</param>
/// <param name="count">The source pointer.</param>
val inline copyBlock : destination: nativeptr<'T> -> source: nativeptr<'T> -> count: int -> unit
23 changes: 18 additions & 5 deletions src/fsharp/FSharp.Core/prim-types-prelude.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -404,8 +404,8 @@ namespace Microsoft.FSharp.Core
/// <summary>Represents an unmanaged pointer in F# code.</summary>
///
/// <remarks>This type should only be used when writing F# code that interoperates
/// with native code. Use of this type in F# code may result in
/// unverifiable code being generated. Conversions to and from the
/// with native code. Use of this type in F# code may result in
/// unverifiable code being generated. Conversions to and from the
/// <see cref="T:Microsoft.FSharp.Core.nativeint" /> type may be required. Values of this type can be generated
/// by the functions in the <c>NativeInterop.NativePtr</c> module.</remarks>
///
Expand All @@ -415,15 +415,28 @@ namespace Microsoft.FSharp.Core
/// <summary>Represents an untyped unmanaged pointer in F# code.</summary>
///
/// <remarks>This type should only be used when writing F# code that interoperates
/// with native code. Use of this type in F# code may result in
/// unverifiable code being generated. Conversions to and from the
/// with native code. Use of this type in F# code may result in
/// unverifiable code being generated. Conversions to and from the
/// <see cref="T:Microsoft.FSharp.Core.nativeint" /> type may be required. Values of this type can be generated
/// by the functions in the <c>NativeInterop.NativePtr</c> module.</remarks>
///
/// <category>ByRef and Pointer Types</category>
type voidptr = (# "void*" #)

/// <summary>This type is for internal use by the F# code generator.</summary>
/// <summary>Represents an Common IL (Intermediate Language) Signature Pointer.</summary>
///
/// <remarks>This type should only be used when writing F# code that interoperates
/// with other .NET languages that use generic Common IL Signature Pointers.
/// Use of this type in F# code may result in unverifiable code being generated.
/// Because of the rules of Common IL Signature Pointers, you cannot use this type in generic type parameters,
/// resulting in compiler errors. As a result, you should convert this type to <see cref="T:Microsoft.FSharp.Core.nativeptr{T}" />
/// for use in F#. Note that Common IL Signature Pointers exposed by other .NET languages are converted to
/// <see cref="T:Microsoft.FSharp.Core.nativeptr{T}" /> or <see cref="T:Microsoft.FSharp.Core.voidptr" /> automatically by F#,
/// and F# also shows generic-specialized typed native pointers correctly to other .NET languages as Common IL Signature Pointers.
/// However, generic typed native pointers are shown as <see cref="T:System.IntPtr"/> to other .NET languages.
/// For other languages to interpret generic F# typed native pointers correctly, you should expose this type or
/// <see cref="T:Microsoft.FSharp.Core.voidptr" /> instead of <see cref="T:Microsoft.FSharp.Core.nativeptr{T}" />.
/// Values of this type can be generated by the functions in the <c>NativeInterop.NativePtr</c> module.</remarks>
///
/// <category>ByRef and Pointer Types</category>
type ilsigptr<'T> = (# "!0*" #)
Expand Down
1 change: 0 additions & 1 deletion src/fsharp/IlxGen.fs
Original file line number Diff line number Diff line change
Expand Up @@ -4011,7 +4011,6 @@ and GenAsmCode cenv cgbuf eenv (il, tyargs, args, returnTys, m) sequel =
| I_stobj (a, b, ILType.TypeVar _), [tyarg] -> I_stobj (a, b, tyarg)
| I_ldtoken (ILToken.ILType (ILType.TypeVar _)), [tyarg] -> I_ldtoken (ILToken.ILType tyarg)
| I_sizeof (ILType.TypeVar _), [tyarg] -> I_sizeof tyarg
// currently unused, added for forward compat, see https://visualfsharp.codeplex.com/SourceControl/network/forks/jackpappas/fsharpcontrib/contribution/7134
| I_cpobj (ILType.TypeVar _), [tyarg] -> I_cpobj tyarg
| I_initobj (ILType.TypeVar _), [tyarg] -> I_initobj tyarg
| I_ldfld (al, vol, fspec), _ -> I_ldfld (al, vol, modFieldSpec fspec)
Expand Down
8 changes: 4 additions & 4 deletions src/fsharp/TypedTreePickle.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1183,10 +1183,10 @@ let [<Literal>] itag_ldelem_any = 59
let [<Literal>] itag_stelem_any = 60
let [<Literal>] itag_unbox_any = 61
let [<Literal>] itag_ldlen_multi = 62
let [<Literal>] itag_initobj = 63 // currently unused, added for forward compat, see https://visualfsharp.codeplex.com/SourceControl/network/forks/jackpappas/fsharpcontrib/contribution/7134
let [<Literal>] itag_initblk = 64 // currently unused, added for forward compat
let [<Literal>] itag_cpobj = 65 // currently unused, added for forward compat
let [<Literal>] itag_cpblk = 66 // currently unused, added for forward compat
let [<Literal>] itag_initobj = 63
let [<Literal>] itag_initblk = 64
let [<Literal>] itag_cpobj = 65
let [<Literal>] itag_cpblk = 66

let simple_instrs =
[ itag_add, AI_add
Expand Down
1 change: 1 addition & 0 deletions tests/FSharp.Core.UnitTests/FSharp.Core.UnitTests.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
<Compile Include="FSharp.Core\OperatorsModule1.fs" />
<Compile Include="FSharp.Core\OperatorsModule2.fs" />
<Compile Include="FSharp.Core\OperatorsModuleChecked.fs" />
<Compile Include="FSharp.Core\NativeInterop.fs" />

<Compile Include="FSharp.Core\Microsoft.FSharp.Collections\Utils.fs" />
<Compile Include="FSharp.Core\Microsoft.FSharp.Collections\ArrayModule.fs" />
Expand Down
Loading