mu/baremetal/109stream-equal.subx
Kartik Agaram 49424b1933 7523
There's a dependency cycle here:

- draw-grapheme (Mu) uses read-grapheme (Mu) to be unicode-aware.
- read-grapheme uses read-byte (SubX). Streams are a fundamental data
  structure in Mu. For the Mu compiler to be able to reason about the
  safety of stream operations, they need to be an opaque type. All
  stream primitives are written in SubX. To manipulate a stream's
  internals we force people to reach for SubX. That way if there's no
  SubX code there's confidence that things are safe.
- read-byte and other stream operations have unit tests, like they
  should. The unit tests need to print data to screen when say a test
  fails. To do this they use various check- functions (SubX) that take a
  string argument.
- Printing a string to screen uses draw-grapheme (Mu).

Perhaps I should maintain variants of drawing primitives that operate
only on ASCII.
2021-01-15 21:22:33 -08:00

599 lines
29 KiB
Plaintext

# some primitives for checking stream contents
#
# We need to do this in machine code because streams need to be opaque types,
# and we don't yet support opaque types in Mu.
== code
# instruction effective address register displacement immediate
# . op subop mod rm32 base index scale r32
# . 1-3 bytes 3 bits 2 bits 3 bits 3 bits 3 bits 2 bits 2 bits 0/1/2/4 bytes 0/1/2/4 bytes
# compare all the data in a stream (ignoring the read pointer)
stream-data-equal?: # f: (addr stream byte), s: (addr array byte) -> result/eax: boolean
# . prologue
55/push-ebp
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
# . save registers
51/push-ecx
52/push-edx
56/push-esi
57/push-edi
# esi = f
8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 . # copy *(ebp+8) to esi
# eax = f->write
8b/copy 0/mod/indirect 6/rm32/esi . . . 0/r32/eax . . # copy *esi to eax
# var maxf/edx: (addr byte) = &f->data[f->write]
8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/esi 0/index/eax . 2/r32/edx 0xc/disp8 . # copy esi+eax+12 to edx
# var currf/esi: (addr byte) = f->data
81 0/subop/add 3/mod/direct 6/rm32/esi . . . . . 0xc/imm32 # add to esi
# edi = s
8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 7/r32/edi 0xc/disp8 . # copy *(ebp+12) to edi
$stream-data-equal?:compare-sizes:
# if (f->write != s->size) return false
39/compare 0/mod/indirect 7/rm32/edi . . . 0/r32/eax . . # compare *edi and eax
75/jump-if-!= $stream-data-equal?:false/disp8
# var currs/edi: (addr byte) = s->data
81 0/subop/add 3/mod/direct 7/rm32/edi . . . . . 4/imm32 # add to edi
# var eax: byte = 0
31/xor 3/mod/direct 0/rm32/eax . . . 0/r32/eax . . # clear eax
# var ecx: byte = 0
31/xor 3/mod/direct 1/rm32/ecx . . . 1/r32/ecx . . # clear ecx
$stream-data-equal?:loop:
# if (currf >= maxf) return true
39/compare 3/mod/direct 6/rm32/esi . . . 2/r32/edx . . # compare esi with edx
73/jump-if-addr>= $stream-data-equal?:true/disp8
# AL = *currs
8a/copy-byte 0/mod/indirect 6/rm32/esi . . . 0/r32/AL . . # copy byte at *esi to AL
# CL = *curr
8a/copy-byte 0/mod/indirect 7/rm32/edi . . . 1/r32/CL . . # copy byte at *edi to CL
# if (eax != ecx) return false
39/compare 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . . # compare eax and ecx
75/jump-if-!= $stream-data-equal?:false/disp8
# ++f
46/increment-esi
# ++curr
47/increment-edi
eb/jump $stream-data-equal?:loop/disp8
$stream-data-equal?:false:
b8/copy-to-eax 0/imm32
eb/jump $stream-data-equal?:end/disp8
$stream-data-equal?:true:
b8/copy-to-eax 1/imm32
$stream-data-equal?:end:
# . restore registers
5f/pop-to-edi
5e/pop-to-esi
5a/pop-to-edx
59/pop-to-ecx
# . epilogue
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
5d/pop-to-ebp
c3/return
test-stream-data-equal:
# . prologue
55/push-ebp
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
# clear-stream(_test-stream)
# . . push args
68/push _test-stream/imm32
# . . call
e8/call clear-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
# write(_test-stream, "Abc")
# . . push args
68/push "Abc"/imm32
68/push _test-stream/imm32
# . . call
e8/call write/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
# eax = stream-data-equal?(_test-stream, "Abc")
# . . push args
68/push "Abc"/imm32
68/push _test-stream/imm32
# . . call
e8/call stream-data-equal?/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
# check-ints-equal(eax, 1, msg)
# . . push args
68/push "F - test-stream-data-equal"/imm32
68/push 1/imm32
50/push-eax
# . . call
e8/call check-ints-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
# . epilogue
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
5d/pop-to-ebp
c3/return
test-stream-data-equal-2:
# . prologue
55/push-ebp
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
# clear-stream(_test-stream)
# . . push args
68/push _test-stream/imm32
# . . call
e8/call clear-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
# write(_test-stream, "Abc")
# . . push args
68/push "Abc"/imm32
68/push _test-stream/imm32
# . . call
e8/call write/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
# eax = stream-data-equal?(_test-stream, "Abd")
# . . push args
68/push "Abd"/imm32
68/push _test-stream/imm32
# . . call
e8/call stream-data-equal?/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
# check-ints-equal(eax, 0, msg)
# . . push args
68/push "F - test-stream-data-equal-2"/imm32
68/push 0/imm32
50/push-eax
# . . call
e8/call check-ints-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
# . epilogue
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
5d/pop-to-ebp
c3/return
test-stream-data-equal-size-check:
# . prologue
55/push-ebp
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
# clear-stream(_test-stream)
# . . push args
68/push _test-stream/imm32
# . . call
e8/call clear-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
# write(_test-stream, "Abc")
# . . push args
68/push "Abc"/imm32
68/push _test-stream/imm32
# . . call
e8/call write/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
# eax = stream-data-equal?(_test-stream, "Abcd")
# . . push args
68/push "Abcd"/imm32
68/push _test-stream/imm32
# . . call
e8/call stream-data-equal?/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
# check-ints-equal(eax, 0, msg)
# . . push args
68/push "F - test-stream-data-equal-size-check"/imm32
68/push 0/imm32
50/push-eax
# . . call
e8/call check-ints-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
# . epilogue
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
5d/pop-to-ebp
c3/return
# helper for later tests
check-stream-equal: # f: (addr stream byte), s: (addr array byte), msg: (addr array byte)
# . prologue
55/push-ebp
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
# . save registers
50/push-eax
# eax = stream-data-equal?(f, s)
# . . push args
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12)
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8)
# . . call
e8/call stream-data-equal?/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
# check-ints-equal(eax, 1, msg)
# . . push args
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x10/disp8 . # push *(ebp+16)
68/push 1/imm32
50/push-eax
# . . call
e8/call check-ints-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
$check-stream-equal:end:
# . restore registers
58/pop-to-eax
# . epilogue
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
5d/pop-to-ebp
c3/return
# scan the next line until newline starting from f->read and compare it with
# 's' (ignoring the trailing newline)
# on success, set f->read to after the next newline
# on failure, leave f->read unmodified
# this function is usually used only in tests, so we repeatedly write f->read
next-stream-line-equal?: # f: (addr stream byte), s: (addr array byte) -> result/eax: boolean
# pseudocode:
# currf = f->read # bound: f->write
# currs = 0 # bound: s->size
# while true
# if currf >= f->write
# return currs >= s->size
# if f[currf] == '\n'
# ++currf
# return currs >= s->size
# if (currs >= s->size) return false # the current line of f still has data to match
# if (f[currf] != s[currs]) return false
# ++currf
# ++currs
#
# collapsing the two branches that can return true:
# currf = f->read # bound: f->write
# currs = 0 # bound: s->size
# while true
# if (currf >= f->write) break
# if (f[currf] == '\n') break
# if (currs >= s->size) return false # the current line of f still has data to match
# if (f[currf] != s[currs]) return false
# ++currf
# ++currs
# ++currf # skip '\n'
# return currs >= s->size
# Here the final `++currf` is sometimes unnecessary (if we're already at the end of the stream)
#
# registers:
# f: esi
# s: edi
# currf: ecx
# currs: edx
# f[currf]: eax
# s[currs]: ebx
#
# . prologue
55/push-ebp
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
# . save registers
51/push-ecx
52/push-edx
56/push-esi
57/push-edi
# esi = f
8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 . # copy *(ebp+8) to esi
# var currf/ecx: int = f->read
8b/copy 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 4/disp8 . # copy *(esi+4) to ecx
# edi = s
8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 7/r32/edi 0xc/disp8 . # copy *(ebp+12) to edi
# var currs/edx: int = 0
31/xor 3/mod/direct 2/rm32/edx . . . 2/r32/edx . . # clear edx
# var c1/eax: byte = 0
31/xor 3/mod/direct 0/rm32/eax . . . 0/r32/eax . . # clear eax
# var c2/ebx: byte = 0
31/xor 3/mod/direct 3/rm32/ebx . . . 3/r32/ebx . . # clear ebx
$next-stream-line-equal?:loop:
# if (currf >= f->write) break
3b/compare 0/mod/indirect 6/rm32/esi . . . 1/r32/ecx . . # compare ecx with *esi
7d/jump-if->= $next-stream-line-equal?:break/disp8
# c1 = f->data[f->read]
8a/copy-byte 1/mod/*+disp8 4/rm32/sib 6/base/esi 1/index/ecx . 0/r32/AL 0xc/disp8 . # copy byte at *(esi+ecx+12) to AL
# if (c1 == '\n') break
3d/compare-eax-and 0xa/imm32/newline
74/jump-if-= $next-stream-line-equal?:break/disp8
# if (currs >= s->size) return false
3b/compare 0/mod/indirect 7/rm32/edi . . . 2/r32/edx . . # compare edx with *edi
7d/jump-if->= $next-stream-line-equal?:false/disp8
# c2 = s->data[currs]
8a/copy-byte 1/mod/*+disp8 4/rm32/sib 7/base/edi 2/index/edx . 3/r32/BL 4/disp8 . # copy byte at *(edi+edx+4) to BL
# if (c1 != c2) return false
39/compare 3/mod/direct 0/rm32/eax . . . 3/r32/ebx . . # compare eax and ebx
75/jump-if-!= $next-stream-line-equal?:false/disp8
# ++currf
41/increment-ecx
# ++currs
42/increment-edx
eb/jump $next-stream-line-equal?:loop/disp8
$next-stream-line-equal?:break:
# ++currf
41/increment-ecx
# if (currs >= s->size) return true
3b/compare 0/mod/indirect 7/rm32/edi . . . 2/r32/edx . . # compare edx with *edi
7c/jump-if-< $next-stream-line-equal?:false/disp8
$next-stream-line-equal?:true:
b8/copy-to-eax 1/imm32
# persist f->read on success
89/copy 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 4/disp8 . # copy ecx to *(esi+4)
eb/jump $next-stream-line-equal?:end/disp8
$next-stream-line-equal?:false:
b8/copy-to-eax 0/imm32
$next-stream-line-equal?:end:
# . restore registers
5f/pop-to-edi
5e/pop-to-esi
5a/pop-to-edx
59/pop-to-ecx
# . epilogue
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
5d/pop-to-ebp
c3/return
test-next-stream-line-equal-stops-at-newline:
# . prologue
55/push-ebp
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
# clear-stream(_test-stream)
# . . push args
68/push _test-stream/imm32
# . . call
e8/call clear-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
# write(_test-stream, "Abc\ndef")
# . . push args
68/push "Abc\ndef"/imm32
68/push _test-stream/imm32
# . . call
e8/call write/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
# eax = next-stream-line-equal?(_test-stream, "Abc")
# . . push args
68/push "Abc"/imm32
68/push _test-stream/imm32
# . . call
e8/call next-stream-line-equal?/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
# check-ints-equal(eax, 1, msg)
# . . push args
68/push "F - test-next-stream-line-equal-stops-at-newline"/imm32
68/push 1/imm32
50/push-eax
# . . call
e8/call check-ints-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
# . epilogue
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
5d/pop-to-ebp
c3/return
test-next-stream-line-equal-stops-at-newline-2:
# . prologue
55/push-ebp
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
# clear-stream(_test-stream)
# . . push args
68/push _test-stream/imm32
# . . call
e8/call clear-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
# write(_test-stream, "Abc\ndef")
# . . push args
68/push "Abc\ndef"/imm32
68/push _test-stream/imm32
# . . call
e8/call write/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
# eax = next-stream-line-equal?(_test-stream, "def")
# . . push args
68/push "def"/imm32
68/push _test-stream/imm32
# . . call
e8/call next-stream-line-equal?/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
# check-ints-equal(eax, 0, msg)
# . . push args
68/push "F - test-next-stream-line-equal-stops-at-newline-2"/imm32
68/push 0/imm32
50/push-eax
# . . call
e8/call check-ints-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
# . epilogue
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
5d/pop-to-ebp
c3/return
test-next-stream-line-equal-skips-newline:
# . prologue
55/push-ebp
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
# clear-stream(_test-stream)
# . . push args
68/push _test-stream/imm32
# . . call
e8/call clear-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
# write(_test-stream, "Abc\ndef\n")
# . . push args
68/push "Abc\ndef\n"/imm32
68/push _test-stream/imm32
# . . call
e8/call write/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
# next-stream-line-equal?(_test-stream, "Abc")
# . . push args
68/push "Abc"/imm32
68/push _test-stream/imm32
# . . call
e8/call next-stream-line-equal?/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
# eax = next-stream-line-equal?(_test-stream, "def")
# . . push args
68/push "def"/imm32
68/push _test-stream/imm32
# . . call
e8/call next-stream-line-equal?/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
# check-ints-equal(eax, 1, msg)
# . . push args
68/push "F - test-next-stream-line-equal-skips-newline"/imm32
68/push 1/imm32
50/push-eax
# . . call
e8/call check-ints-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
# . epilogue
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
5d/pop-to-ebp
c3/return
test-next-stream-line-equal-handles-final-line:
# . prologue
55/push-ebp
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
# clear-stream(_test-stream)
# . . push args
68/push _test-stream/imm32
# . . call
e8/call clear-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
# write(_test-stream, "Abc\ndef")
# . . push args
68/push "Abc\ndef"/imm32
68/push _test-stream/imm32
# . . call
e8/call write/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
# next-stream-line-equal?(_test-stream, "Abc")
# . . push args
68/push "Abc"/imm32
68/push _test-stream/imm32
# . . call
e8/call next-stream-line-equal?/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
# eax = next-stream-line-equal?(_test-stream, "def")
# . . push args
68/push "def"/imm32
68/push _test-stream/imm32
# . . call
e8/call next-stream-line-equal?/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
# check-ints-equal(eax, 1, msg)
# . . push args
68/push "F - test-next-stream-line-equal-skips-newline"/imm32
68/push 1/imm32
50/push-eax
# . . call
e8/call check-ints-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
# . epilogue
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
5d/pop-to-ebp
c3/return
test-next-stream-line-equal-always-fails-after-Eof:
# . prologue
55/push-ebp
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
# clear-stream(_test-stream)
# . . push args
68/push _test-stream/imm32
# . . call
e8/call clear-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
# write nothing
# eax = next-stream-line-equal?(_test-stream, "")
# . . push args
68/push ""/imm32
68/push _test-stream/imm32
# . . call
e8/call next-stream-line-equal?/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
# check-ints-equal(eax, 0, msg)
# . . push args
68/push "F - test-next-stream-line-equal-always-fails-after-Eof"/imm32
68/push 1/imm32
50/push-eax
# . . call
e8/call check-ints-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
# eax = next-stream-line-equal?(_test-stream, "")
# . . push args
68/push ""/imm32
68/push _test-stream/imm32
# . . call
e8/call next-stream-line-equal?/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
# check-ints-equal(eax, 0, msg)
# . . push args
68/push "F - test-next-stream-line-equal-always-fails-after-Eof/2"/imm32
68/push 1/imm32
50/push-eax
# . . call
e8/call check-ints-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
# . epilogue
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
5d/pop-to-ebp
c3/return
# helper for later tests
check-next-stream-line-equal: # f: (addr stream byte), s: (addr array byte), msg: (addr array byte)
# . prologue
55/push-ebp
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
# . save registers
50/push-eax
# eax = next-stream-line-equal?(f, s)
# . . push args
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12)
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8)
# . . call
e8/call next-stream-line-equal?/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
# check-ints-equal(eax, 1, msg)
# . . push args
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x10/disp8 . # push *(ebp+16)
68/push 1/imm32
50/push-eax
# . . call
e8/call check-ints-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
# . restore registers
58/pop-to-eax
# . epilogue
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
5d/pop-to-ebp
c3/return
# . . vim:nowrap:textwidth=0