Last active
May 22, 2018 07:39
-
-
Save mrange/f5b2ebe34a2bf47da7521d46946a61f6 to your computer and use it in GitHub Desktop.
Another take at Transducers
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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