Skip to content

Instantly share code, notes, and snippets.

@mrange
Last active May 22, 2018 07:39
Show Gist options
  • Save mrange/f5b2ebe34a2bf47da7521d46946a61f6 to your computer and use it in GitHub Desktop.
Save mrange/f5b2ebe34a2bf47da7521d46946a61f6 to your computer and use it in GitHub Desktop.
Another take at Transducers
module FsTransducers =
type Context =
{
mutable Continue : bool
}
static member New () : Context = { Continue = true }
type Initializer = Context -> unit
type Folder<'S, 'T> = 'S -> 'T -> 'S
type Completer<'S> = Context -> 'S -> 'S
type [<Struct>] Reducer<'S, 'T> = R of (Initializer*Folder<'S, 'T>*Completer<'S>)
type [<Struct>] Transducer<'S, 'T, 'U> = T of (Reducer<'S, 'U> -> Reducer<'S, 'T>)
module Transducer =
module Details =
type OF<'A, 'B, 'C> = OptimizedClosures.FSharpFunc<'A, 'B, 'C>
let inline adapt f = OF<_, _, _>.Adapt f
let inline invoke (f : OF<_, _, _>) s t = f.Invoke (s, t)
let init ctx = ()
let completer ctx s = s
let inline buildUp (T t) step = t (R (init, step, completer))
module Loops =
let inline cont (ctx : Context) = ctx.Continue
let rec foldResizeArray ctx step s (ra : ResizeArray<_>) c =
if cont ctx && c < ra.Count then
foldResizeArray ctx step (invoke step s ra.[c]) ra (c + 1)
else
s
let rec foldRange ctx step s e c =
if cont ctx && c < e then
foldRange ctx step (invoke step s c) e (c + 1)
else
s
let rec foldArray ctx step s (vs : _ []) c =
if cont ctx && c < vs.Length then
foldArray ctx step (invoke step s vs.[c]) vs (c + 1)
else
s
open Details
open System
open System.Collections.Generic
let inline combine (T t) (T u) = T (u >> t)
let inline filter f =
T <| function
R (init, step, completer) ->
let step = adapt step
let next s t = if f t then invoke step s t else s
R (init, next, completer)
let inline map m =
T <| function
R (init, step, completer) ->
let step = adapt step
let next s t = invoke step s (m t)
R (init, next, completer)
let inline sortBy sel =
T <| function
R (init, step, completer) ->
let inline compareTo (l : #IComparable<_>) r = l.CompareTo r
let step = adapt step
let ra = ResizeArray 16
let init ctx =
ra.Clear ()
init ctx
let next s t =
ra.Add t
s
let completer ctx s =
let comp =
{ new IComparer<_> with
member x.Compare (l, r) =
let lv = sel l
let rv = sel r
compareTo lv rv
}
ra.Sort comp
let s = Loops.foldResizeArray ctx step s ra 0
ra.Clear ()
let s = completer ctx s
s
R (init, next, completer)
let inline foldRange t f s b e =
let (R (init, step, completer)) = buildUp t f
let ctx = Context.New ()
init ctx
let step = adapt step
let s = Loops.foldRange ctx step s e b
let completer = adapt completer
invoke completer ctx s
let inline foldArray t f s vs =
let (R (init, step, completer)) = buildUp t f
let ctx = Context.New ()
init ctx
let step = adapt step
let s = Loops.foldArray ctx step s vs 0
let completer = adapt completer
invoke completer ctx s
let inline toArray tf vs =
let ra = ResizeArray 16
foldArray tf (fun () v -> ra.Add v) () vs
ra.ToArray ()
type Transducer<'S, 'T, 'U> with
static member (>->) (t, u) = Transducer.combine t u
module Tests =
open FsCheck
open Transducer
type Properties () =
static member ``filter`` (vs : int []) =
let f v = v &&& 1 = 0
let e = vs |> Array.filter f
let a = toArray (filter f) vs
e = a
static member ``map`` (vs : int []) =
let m v = int64 v + 1L
let e = vs |> Array.map m
let a = toArray (map m) vs
e = a
static member ``sortBy`` (vs : int []) =
let asc =
let sel v = v
let e = vs |> Array.sortBy sel
let a = toArray (sortBy sel) vs
e = a
let desc =
let sel v = -v
let e = vs |> Array.sortBy sel
let a = toArray (sortBy sel) vs
e = a
asc && desc
static member ``combine(simple)`` (vs : int []) =
let f v = v &&& 1 = 0
let m v = int64 v + 1L
let e = vs |> Array.filter f |> Array.map m
let a = toArray (filter f >-> map m) vs
e = a
static member ``combine(post-process)`` (vs : int []) =
let f v = v &&& 1 = 0
let m v = int64 v + 1L
let sel v = -v
let e = vs |> Array.sortBy sel |> Array.filter f |> Array.map m
let a = toArray (sortBy sel >-> filter f >-> map m) vs
e = a
static member ``combine(post-processx2)`` (vs : int []) =
let f v = v &&& 1 = 0
let m v = int64 v + 1L
let sel v = -v
let e = vs |> Array.sortBy sel |> Array.filter f |> Array.map m |> Array.sortBy id
let a = toArray (sortBy sel >-> filter f >-> map m >-> sortBy id) vs
e = a
let run () =
let config = { Config.Quick with MaxTest = 1000; MaxRejected = 1000 }
Check.All<Properties> config
module FsTransducers2 =
open System
open System.Collections.Generic
type Folder<'S, 'T> = 'S -> 'T -> 'S
type Completer<'S> = 'S -> 'S
type [<Struct>] Transducer<'S, 'T, 'U> =
| Simple of s:(Folder<'S, 'U> -> Folder<'S, 'T>)
| PostProcess of p:(unit -> struct((Folder<'S, 'U> -> Folder<'S, 'T>)*(Completer<'S> -> Completer<'S> )))
module Transducer =
module Details =
type OF<'S, 'T> = OptimizedClosures.FSharpFunc<'S, 'T, 'S>
let inline adapt f = OF<_, _>.Adapt f
let inline invoke (f : OF<_, _>) s t = f.Invoke (s, t)
let inline extract t =
match t with
| Simple tf -> struct (tf, id)
| PostProcess tp -> tp ()
module Loops =
let rec foldResizeArray n s (ra : ResizeArray<_>) i =
if i < ra.Count then
foldResizeArray n (invoke n s ra.[i]) ra (i + 1)
else
s
let rec foldRange tf s e c =
if c < e then
foldRange tf (invoke tf s c) e (c + 1)
else
s
let rec foldArray tf s (vs : _ []) c =
if c < vs.Length then
foldArray tf (invoke tf s vs.[c]) vs (c + 1)
else
s
open Details
// Pipes
let inline combine t u =
match t, u with
| Simple tf, Simple uf ->
Simple <| fun next ->
tf (uf next)
| Simple tf, PostProcess up ->
let t () =
let struct (uf, uc) = up ()
let f next =
tf (uf next)
struct (f, uc)
PostProcess <| t
| PostProcess tp, Simple uf ->
let t () =
let struct (tf, tc) = tp ()
let f next =
tf (uf next)
struct (f, tc)
PostProcess <| t
| PostProcess tp, PostProcess up ->
let t () =
let struct (tf, tc) = tp ()
let struct (uf, uc) = up ()
let f next =
tf (uf next)
let c next =
tc (uc next)
struct (f, c)
PostProcess <| t
let inline filter f =
Simple <| fun next ->
let next = adapt next
fun s t ->
if f t then
invoke next s t
else
s
let inline map m =
Simple <| fun next ->
let next = adapt next
fun s t ->
invoke next s (m t)
let inline sortBy sel =
let inline compareTo (l : #IComparable<_>) r = l.CompareTo r
let t () =
let ra = ResizeArray 16
let mutable n = Unchecked.defaultof<_>
let f next =
n <- adapt next
fun s t ->
ra.Add t
s
let c next =
fun s ->
let comp =
{ new IComparer<_> with
member x.Compare (l, r) =
let lv = sel l
let rv = sel r
compareTo lv rv
}
ra.Sort comp
let s = Loops.foldResizeArray n s ra 0
ra.Clear ()
next s
struct (f, c)
PostProcess <| t
// Folders
let inline foldRange t f s b e =
let struct (tf, tc) = extract t
let tf = tf f
let tf = adapt tf
let s = Loops.foldRange tf s e b
tc id s
let inline foldArray t f s vs =
let struct (tf, tc) = extract t
let tf = tf f
let tf = adapt tf
let s = Loops.foldArray tf s vs 0
tc id s
let inline toArray t vs =
let ra = ResizeArray 16
foldArray t (fun () v -> ra.Add v) () vs
ra.ToArray ()
type Transducer<'S, 'T, 'U> with
static member (>->) (t, u) = Transducer.combine t u
module Tests =
open FsCheck
open Transducer
type Properties () =
static member ``filter`` (vs : int []) =
let f v = v &&& 1 = 0
let e = vs |> Array.filter f
let a = toArray (filter f) vs
e = a
static member ``map`` (vs : int []) =
let m v = int64 v + 1L
let e = vs |> Array.map m
let a = toArray (map m) vs
e = a
static member ``sortBy`` (vs : int []) =
let asc =
let sel v = v
let e = vs |> Array.sortBy sel
let a = toArray (sortBy sel) vs
e = a
let desc =
let sel v = -v
let e = vs |> Array.sortBy sel
let a = toArray (sortBy sel) vs
e = a
asc && desc
static member ``combine(simple)`` (vs : int []) =
let f v = v &&& 1 = 0
let m v = int64 v + 1L
let e = vs |> Array.filter f |> Array.map m
let a = toArray (filter f >-> map m) vs
e = a
static member ``combine(post-process)`` (vs : int []) =
let f v = v &&& 1 = 0
let m v = int64 v + 1L
let sel v = -v
let e = vs |> Array.sortBy sel |> Array.filter f |> Array.map m
let a = toArray (sortBy sel >-> filter f >-> map m) vs
e = a
static member ``combine(post-processx2)`` (vs : int []) =
let f v = v &&& 1 = 0
let m v = int64 v + 1L
let sel v = -v
let e = vs |> Array.sortBy sel |> Array.filter f |> Array.map m |> Array.sortBy id
let a = toArray (sortBy sel >-> filter f >-> map m >-> sortBy id) vs
e = a
let run () =
let config = { Config.Quick with MaxTest = 1000; MaxRejected = 1000 }
Check.All<Properties> config
module Streams =
module PerformanceTests =
type SimplisticStream<'T> = ('T -> unit) -> unit
module SimplisticStream =
module Details =
let inline adapt f = OptimizedClosures.FSharpFunc<_, _, _>.Adapt f
let inline invoke (f : OptimizedClosures.FSharpFunc<_, _, _>) s t = f.Invoke (s, t)
module Loops =
let rec fromRange r e c =
if c < e then
r c
fromRange r e (c + 1)
open Details
let empty<'T> : SimplisticStream<'T> = fun _ -> ()
let inline singleton v : SimplisticStream<_> = fun r -> r v
let inline map m ss : SimplisticStream<_> = fun r -> ss (fun v -> r (m v))
let inline filter f ss : SimplisticStream<_> = fun r -> ss (fun v -> if f v then r v)
let fromRange b e : SimplisticStream<_> = fun r ->
Loops.fromRange r e b
let inline sum (ss : SimplisticStream<_>) =
let mutable s = LanguagePrimitives.GenericZero<_>
ss (fun v -> s <- s + v) |> ignore
s
type [<Struct>] PushStream<'T> = PS of (('T -> bool) -> bool)
module PushStream =
module Details =
let inline adapt f = OptimizedClosures.FSharpFunc<_, _, _>.Adapt f
let inline invoke (f : OptimizedClosures.FSharpFunc<_, _, _>) s t = f.Invoke (s, t)
module Loops =
let rec fromRange r e c =
if c < e then
r c && fromRange r e (c + 1)
else
true
open Details
let empty<'T> : PushStream<'T> = PS <| fun _ -> true
let inline singleton v = PS <| fun r -> r v
let inline map m (PS ps) = PS <| fun r -> ps (m >> r)
let inline filter f (PS ps) = PS <| fun r -> ps (fun v -> if f v then r v else true)
let inline collect m (PS ps) = PS <| fun r -> ps (fun v -> let (PS ips) = m v in ips r)
let fromRange b e = PS <| fun r ->
Loops.fromRange r e b
let inline fold f z (PS ps) =
let mutable s = z
let f = adapt f
ps (fun v -> s <- invoke f s v; true) |> ignore
s
let inline sum (PS ps) =
let mutable s = LanguagePrimitives.GenericZero<_>
ps (fun v -> s <- s + v; true) |> ignore
s
let dbreak () = System.Diagnostics.Debugger.Break ()
// now () returns current time in milliseconds since start
let now : unit -> int64 =
let sw = System.Diagnostics.Stopwatch ()
sw.Start ()
fun () -> sw.ElapsedMilliseconds
// time estimates the time 'action' repeated a number of times
let time repeat init action () =
let inline cc i = System.GC.CollectionCount i
let input = init ()
System.GC.Collect (2, System.GCCollectionMode.Forced, true)
let v = action input
let bcc0, bcc1, bcc2 = cc 0, cc 1, cc 2
let b = now ()
for i in 1..repeat do
action input |> ignore
let e = now ()
let ecc0, ecc1, ecc2 = cc 0, cc 1, cc 2
v, e - b, ecc0 - bcc0, ecc1 - bcc1, ecc2 - bcc2
let createTestCases outer inner =
let perfSeq =
let init () =
()
let action () =
Seq.init inner id
|> Seq.map ((+)1)
|> Seq.filter (fun v -> v &&& 1 = 0)
|> Seq.map int64
|> Seq.sum
"Seq" , time outer init action
let perfImperative =
let rec loop s i =
if i < inner then
let j = i + 1
if j &&& 1 = 0 then
loop (s + int64 j) (i + 1)
else
loop s (i + 1)
else
s
let init () =
()
let action () =
loop 0L 0
"Imperative" , time outer init action
let perfSimplisticStream =
let init () =
()
let action () =
SimplisticStream.fromRange 0 inner
|> SimplisticStream.map ((+)1)
|> SimplisticStream.filter (fun v -> v &&& 1 = 0)
|> SimplisticStream.map int64
|> SimplisticStream.sum
"SimplisticStream" , time outer init action
let perfPushStream =
let init () =
()
let action () =
PushStream.fromRange 0 inner
|> PushStream.map ((+)1)
|> PushStream.filter (fun v -> v &&& 1 = 0)
|> PushStream.map int64
|> PushStream.sum
"PushStream" , time outer init action
let perfTransducer =
let init () =
FsTransducers.Transducer.map ((+)1)
>-> FsTransducers.Transducer.filter (fun v -> v &&& 1 = 0)
>-> FsTransducers.Transducer.map int64
let action t =
FsTransducers.Transducer.foldRange t (+) 0L 0 inner
"Transducer" , time outer init action
let perfTransducer2 =
let init () =
FsTransducers2.Transducer.map ((+)1)
>-> FsTransducers2.Transducer.filter (fun v -> v &&& 1 = 0)
>-> FsTransducers2.Transducer.map int64
let action (t : FsTransducers2.Transducer<int64,_,_ >) =
FsTransducers2.Transducer.foldRange t (+) 0L 0 inner
"Transducer2" , time outer init action
[|
// perfSeq
perfSimplisticStream
perfPushStream
perfTransducer
perfTransducer2
perfImperative
|]
let run () =
do
let total = 100_000
let outer = 1_000
let inner = total / outer
let testCases = createTestCases outer inner
for name, action in testCases do
printfn "Warm-up testCase '%s'" name
action () |> ignore
do
let total = 1_000_000_00
let outers =
[|
1
10
1000
100000
10000000
|]
for outer in outers do
let inner = total / outer
let testCases = createTestCases outer inner
for name, action in testCases do
printfn "Running testCase '%s'..." name
let v, ms, cc0, cc1, cc2 = action ()
printfn " Result is: %A, it took %d ms and ran CC (%d, %d, %d)" v ms cc0 cc1 cc2
[<EntryPoint>]
let main argv =
#if !RELEASE
FsTransducers.Tests.run ()
FsTransducers2.Tests.run ()
#else
Streams.PerformanceTests.run ()
#endif
0
# Simplistic
00007ffd`30706980 3bfe cmp edi,esi
00007ffd`30706982 7d13 jge 00007ffd`30706997
00007ffd`30706984 488bcb mov rcx,rbx
00007ffd`30706987 8bd7 mov edx,edi
00007ffd`30706989 488b03 mov rax,qword ptr [rbx]
00007ffd`3070698c 488b4040 mov rax,qword ptr [rax+40h]
00007ffd`30706990 ff5020 call qword ptr [rax+20h] ds:00007ffd`307cdec8=00007ffd307069c0
00007ffd`30706993 ffc7 inc edi
00007ffd`30706995 ebe9 jmp 00007ffd`30706980
00007ffd`307069c0 488b4908 mov rcx,qword ptr [rcx+8] ds:00000181`8c574b68=000001818c574b48
00007ffd`307069c4 ffc2 inc edx
00007ffd`307069c6 488b01 mov rax,qword ptr [rcx]
00007ffd`307069c9 488b4040 mov rax,qword ptr [rax+40h]
00007ffd`307069cd 488b4020 mov rax,qword ptr [rax+20h]
00007ffd`307069d1 48ffe0 jmp rax
00007ffd`307069f0 8bc2 mov eax,edx
00007ffd`307069f2 448bc0 mov r8d,eax
00007ffd`307069f5 41c1e81f shr r8d,1Fh
00007ffd`307069f9 4403c0 add r8d,eax
00007ffd`307069fc 4183e0fe and r8d,0FFFFFFFEh
00007ffd`30706a00 412bc0 sub eax,r8d
00007ffd`30706a03 7512 jne 00007ffd`30706a17
00007ffd`30706a05 488b4908 mov rcx,qword ptr [rcx+8]
00007ffd`30706a09 488b01 mov rax,qword ptr [rcx]
00007ffd`30706a0c 488b4040 mov rax,qword ptr [rax+40h]
00007ffd`30706a10 488b4020 mov rax,qword ptr [rax+20h]
00007ffd`30706a14 48ffe0 jmp rax
00007ffd`30706a17 33c0 xor eax,eax
00007ffd`30706a19 c3 ret
00007ffd`30706a30 488b4908 mov rcx,qword ptr [rcx+8] ds:00000181`8c574b38=000001818c574b18
00007ffd`30706a34 4863d2 movsxd rdx,edx
00007ffd`30706a37 488b01 mov rax,qword ptr [rcx]
00007ffd`30706a3a 488b4040 mov rax,qword ptr [rax+40h]
00007ffd`30706a3e 488b4020 mov rax,qword ptr [rax+20h]
00007ffd`30706a42 48ffe0 jmp rax
00007ffd`30706a60 488b4108 mov rax,qword ptr [rcx+8] ds:00000181`8c574b20=000001818c574b00
00007ffd`30706a64 488bc8 mov rcx,rax
00007ffd`30706a67 48035008 add rdx,qword ptr [rax+8]
00007ffd`30706a6b 48895108 mov qword ptr [rcx+8],rdx
00007ffd`30706a6f 33c0 xor eax,eax
00007ffd`30706a71 c3 ret
# Transducer
00007ffd`306f7ebf 3bef cmp ebp,edi
00007ffd`306f7ec1 7d17 jge 00007ffd`306f7eda
00007ffd`306f7ec3 488bcb mov rcx,rbx
00007ffd`306f7ec6 448bc5 mov r8d,ebp
00007ffd`306f7ec9 488b03 mov rax,qword ptr [rbx]
00007ffd`306f7ecc 488b4040 mov rax,qword ptr [rax+40h]
00007ffd`306f7ed0 ff5028 call qword ptr [rax+28h]
00007ffd`306f7ed3 488bd0 mov rdx,rax
00007ffd`306f7ed6 ffc5 inc ebp
00007ffd`306f7ed8 ebe5 jmp 00007ffd`306f7ebf
00007ffd`306f85b0 41ffc0 inc r8d
00007ffd`306f85b3 488b4908 mov rcx,qword ptr [rcx+8]
00007ffd`306f85b7 488b01 mov rax,qword ptr [rcx]
00007ffd`306f85ba 488b4040 mov rax,qword ptr [rax+40h]
00007ffd`306f85be 488b4028 mov rax,qword ptr [rax+28h]
00007ffd`306f85c2 48ffe0 jmp rax
00007ffd`306f85e0 418bc0 mov eax,r8d
00007ffd`306f85e3 448bc8 mov r9d,eax
00007ffd`306f85e6 41c1e91f shr r9d,1Fh
00007ffd`306f85ea 4403c8 add r9d,eax
00007ffd`306f85ed 4183e1fe and r9d,0FFFFFFFEh
00007ffd`306f85f1 412bc1 sub eax,r9d
00007ffd`306f85f4 7512 jne 00007ffd`306f8608
00007ffd`306f85f6 488b4908 mov rcx,qword ptr [rcx+8]
00007ffd`306f85fa 488b01 mov rax,qword ptr [rcx]
00007ffd`306f85fd 488b4040 mov rax,qword ptr [rax+40h]
00007ffd`306f8601 488b4028 mov rax,qword ptr [rax+28h]
00007ffd`306f8605 48ffe0 jmp rax
00007ffd`306f8608 488bc2 mov rax,rdx
00007ffd`306f860b c3 ret
00007ffd`306f8620 4d63c0 movsxd r8,r8d
00007ffd`306f8623 488b4908 mov rcx,qword ptr [rcx+8]
00007ffd`306f8627 488b01 mov rax,qword ptr [rcx]
00007ffd`306f862a 488b4040 mov rax,qword ptr [rax+40h]
00007ffd`306f862e 488b4028 mov rax,qword ptr [rax+28h]
00007ffd`306f8632 48ffe0 jmp rax
00007ffd`306f8650 4a8d0402 lea rax,[rdx+r8]
00007ffd`306f8654 c3 ret
# Push Stream
00007ffd`30716d4f 3bf3 cmp esi,ebx
00007ffd`30716d51 7d21 jge 00007ffd`30716d74
00007ffd`30716d53 488bcf mov rcx,rdi
00007ffd`30716d56 8bd6 mov edx,esi
00007ffd`30716d58 488b07 mov rax,qword ptr [rdi]
00007ffd`30716d5b 488b4040 mov rax,qword ptr [rax+40h]
00007ffd`30716d5f ff5020 call qword ptr [rax+20h]
00007ffd`30716d62 84c0 test al,al
00007ffd`30716d64 7404 je 00007ffd`30716d6a
00007ffd`30716d66 ffc6 inc esi
00007ffd`30716d68 ebe5 jmp 00007ffd`30716d4f
00007ffd`30716da0 488b4908 mov rcx,qword ptr [rcx+8] ds:0000027c`00006af0=0000027c00006ad0
00007ffd`30716da4 ffc2 inc edx
00007ffd`30716da6 488b01 mov rax,qword ptr [rcx]
00007ffd`30716da9 488b4040 mov rax,qword ptr [rax+40h]
00007ffd`30716dad 488b4020 mov rax,qword ptr [rax+20h]
00007ffd`30716db1 48ffe0 jmp rax
00007ffd`30716dd0 8bc2 mov eax,edx
00007ffd`30716dd2 448bc0 mov r8d,eax
00007ffd`30716dd5 41c1e81f shr r8d,1Fh
00007ffd`30716dd9 4403c0 add r8d,eax
00007ffd`30716ddc 4183e0fe and r8d,0FFFFFFFEh
00007ffd`30716de0 412bc0 sub eax,r8d
00007ffd`30716de3 7512 jne 00007ffd`30716df7
00007ffd`30716de5 488b4908 mov rcx,qword ptr [rcx+8]
00007ffd`30716de9 488b01 mov rax,qword ptr [rcx]
00007ffd`30716dec 488b4040 mov rax,qword ptr [rax+40h]
00007ffd`30716df0 488b4020 mov rax,qword ptr [rax+20h]
00007ffd`30716df4 48ffe0 jmp rax
00007ffd`30716df7 b801000000 mov eax,1
00007ffd`30716dfc c3 ret
00007ffd`30716e10 488b4908 mov rcx,qword ptr [rcx+8] ds:0000027c`00006ac0=0000027c00006aa0
00007ffd`30716e14 4863d2 movsxd rdx,edx
00007ffd`30716e17 488b01 mov rax,qword ptr [rcx]
00007ffd`30716e1a 488b4040 mov rax,qword ptr [rax+40h]
00007ffd`30716e1e 488b4020 mov rax,qword ptr [rax+20h]
00007ffd`30716e22 48ffe0 jmp rax
00007ffd`30716e40 488b4108 mov rax,qword ptr [rcx+8] ds:0000027c`00006aa8=0000027c00006a88
00007ffd`30716e44 488bc8 mov rcx,rax
00007ffd`30716e47 48035008 add rdx,qword ptr [rax+8]
00007ffd`30716e4b 48895108 mov qword ptr [rcx+8],rdx
00007ffd`30716e4f b801000000 mov eax,1
00007ffd`30716e54 c3 ret
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment