https://github.com/akkartik/mu/blob/main/linux/131table.subx
   1 # A table is a stream of (key, value) rows.
   2 #
   3 # Each row consists of an 8-byte key -- a (handle array byte) -- and a variable-size value.
   4 #
   5 # Accessing the table performs a linear scan for a key string, and always
   6 # requires passing in the row size.
   7 #
   8 # Table primitives have the form <variant>(stream, <arg>, row-size, ...) -> address/eax
   9 #
  10 # The following table shows available options for <variant>:
  11 #   if not found:           | arg=string              arg=slice
  12 #   ------------------------+---------------------------------------------------
  13 #   abort                   | get                     get-slice
  14 #   insert key              | get-or-insert           get-or-insert-slice
  15 #                           | get-or-insert-handle
  16 #   stop                    | get-or-stop             get-slice-or-stop
  17 #   return null             | maybe-get               maybe-get-slice
  18 # Some variants may take extra args.
  19 
  20 == code
  21 #   instruction                     effective address                                                   register    displacement    immediate
  22 # . op          subop               mod             rm32          base        index         scale       r32
  23 # . 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
  24 
  25 # if no row is found, abort
  26 get:  # table: (addr stream {(handle array byte), T}), key: (addr array byte), row-size: int, abort-message-prefix: (addr array byte) -> result/eax: (addr T)
  27     # pseudocode:
  28     #   curr = table->data
  29     #   max = &table->data[table->write]
  30     #   while curr < max
  31     #     var c: (addr array byte) = lookup(*curr)
  32     #     if string-equal?(key, c)
  33     #       return curr+8
  34     #     curr += row-size
  35     #   abort
  36     #
  37     # . prologue
  38     55/push-ebp
  39     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
  40     # . save registers
  41     51/push-ecx
  42     52/push-edx
  43     56/push-esi
  44     # esi = table
  45     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
  46     # var curr/ecx: (addr handle array byte) = table->data
  47     8d/copy-address                 1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   0xc/disp8       .                 # copy esi+12 to ecx
  48     # var max/edx: (addr byte) = &table->data[table->write]
  49     8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           2/r32/edx   .               .                 # copy *esi to edx
  50     8d/copy-address                 0/mod/indirect  4/rm32/sib    1/base/ecx  2/index/edx   .           2/r32/edx   .               .                 # copy ecx+edx to edx
  51 $get:search-loop:
  52     # if (curr >= max) abort
  53     39/compare                      3/mod/direct    1/rm32/ecx    .           .             .           2/r32/edx   .               .                 # compare ecx with edx
  54     73/jump-if-addr>=  $get:abort/disp8
  55     # var c/eax: (addr array byte) = lookup(*curr)
  56     # . . push args
  57     ff          6/subop/push        1/mod/*+disp8   1/rm32/ecx    .           .             .           .           4/disp8         .                 # push *(ecx+4)
  58     ff          6/subop/push        0/mod/indirect  1/rm32/ecx    .           .             .           .           .               .                 # push *ecx
  59     # . . call
  60     e8/call  lookup/disp32
  61     # . . discard args
  62     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
  63     # if (string-equal?(key, c)) return curr+8
  64     # . eax = string-equal?(key, c)
  65     # . . push args
  66     50/push-eax
  67     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
  68     # . . call
  69     e8/call  string-equal?/disp32
  70     # . . discard args
  71     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
  72     # . if (eax != false) return eax = curr+8
  73     3d/compare-eax-and  0/imm32/false
  74     74/jump-if-=  $get:mismatch/disp8
  75     8d/copy-address                 1/mod/*+disp8   1/rm32/ecx    .           .             .           0/r32/eax   8/disp8         .                 # copy ecx+8 to eax
  76     eb/jump  $get:end/disp8
  77 $get:mismatch:
  78     # curr += row-size
  79     03/add                          1/mod/*+disp8   5/rm32/ebp    .           .             .           1/r32/ecx   0x10/disp8      .                 # add *(ebp+16) to ecx
  80     # loop
  81     eb/jump  $get:search-loop/disp8
  82 $get:end:
  83     # . restore registers
  84     5e/pop-to-esi
  85     5a/pop-to-edx
  86     59/pop-to-ecx
  87     # . epilogue
  88     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
  89     5d/pop-to-ebp
  90     c3/return
  91 
  92 $get:abort:
  93     # . _write(2/stderr, abort-message-prefix)
  94     # . . push args
  95     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x14/disp8      .                 # push *(ebp+20)
  96     68/push  2/imm32/stderr
  97     # . . call
  98     e8/call  _write/disp32
  99     # . . discard args
 100     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
 101     # . _write(2/stderr, error)
 102     # . . push args
 103     68/push  ": get: key not found: "/imm32
 104     68/push  2/imm32/stderr
 105     # . . call
 106     e8/call  _write/disp32
 107     # . . discard args
 108     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
 109     # . _write(2/stderr, key)
 110     # . . push args
 111     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
 112     68/push  2/imm32/stderr
 113     # . . call
 114     e8/call  _write/disp32
 115     # . . discard args
 116     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
 117     # . _write(2/stderr, "\n")
 118     # . . push args
 119     68/push  Newline/imm32
 120     68/push  2/imm32/stderr
 121     # . . call
 122     e8/call  _write/disp32
 123     # . . discard args
 124     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
 125     # . syscall(exit, 1)
 126     bb/copy-to-ebx  1/imm32
 127     e8/call  syscall_exit/disp32
 128     # never gets here
 129 
 130 test-get:
 131     # . prologue
 132     55/push-ebp
 133     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
 134     # - setup: create a table with a couple of keys
 135     # var table/ecx: (stream {(handle array byte), number} 24)  # 2 rows * 12 bytes/row
 136     81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               0x18/imm32        # subtract from esp
 137     68/push  0x18/imm32/size
 138     68/push  0/imm32/read
 139     68/push  0/imm32/write
 140     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
 141     # insert(table, "code", 12 bytes/row, Heap)
 142     # . . push args
 143     68/push  Heap/imm32
 144     68/push  0xc/imm32/row-size
 145     68/push  "code"/imm32
 146     51/push-ecx
 147     # . . call
 148     e8/call  get-or-insert/disp32
 149     # . . discard args
 150     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
 151     # insert(table, "data", 12 bytes/row, Heap)
 152     # . . push args
 153     68/push  Heap/imm32
 154     68/push  0xc/imm32/row-size
 155     68/push  "data"/imm32
 156     51/push-ecx
 157     # . . call
 158     e8/call  get-or-insert/disp32
 159     # . . discard args
 160     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
 161 $test-get:check1:
 162     # eax = get(table, "code", 12 bytes/row)
 163     # . . push args
 164     68/push  0xc/imm32/row-size
 165     68/push  "code"/imm32
 166     51/push-ecx
 167     # . . call
 168     e8/call  get/disp32
 169     # . . discard args
 170     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
 171     # check-ints-equal(eax - table->data, 8, msg)
 172     # . check-ints-equal(eax - table, 20, msg)
 173     # . . push args
 174     68/push  "F - test-get/0"/imm32
 175     68/push  0x14/imm32
 176     29/subtract                     3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # subtract ecx from eax
 177     50/push-eax
 178     # . . call
 179     e8/call  check-ints-equal/disp32
 180     # . . discard args
 181     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
 182 $test-get:check2:
 183     # eax = get(table, "data", 12 bytes/row)
 184     # . . push args
 185     68/push  0xc/imm32/row-size
 186     68/push  "data"/imm32
 187     51/push-ecx
 188     # . . call
 189     e8/call  get/disp32
 190     # . . discard args
 191     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
 192     # check-ints-equal(eax - table->data, 20, msg)
 193     # . check-ints-equal(eax - table, 32, msg)
 194     # . . push args
 195     68/push  "F - test-get/1"/imm32
 196     68/push  0x20/imm32
 197     29/subtract                     3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # subtract ecx from eax
 198     50/push-eax
 199     # . . call
 200     e8/call  check-ints-equal/disp32
 201     # . . discard args
 202     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
 203 $test-get:end:
 204     # . epi
# copy ebp to esp 206 5d/pop-to-ebp 207 c3/return 208 209 # if no row is found, abort 210 get-slice: # table: (addr stream {(handle array byte), T}), key: (addr slice), row-size: int, abort-message-prefix: (addr array byte) -> result/eax: (addr T) 211 # pseudocode: 212 # curr = table->data 213 # max = &table->data[table->write] 214 # while curr < max 215 # var c: (addr array byte) = lookup(*curr) 216 # if slice-equal?(key, c) 217 # return curr+8 218 # curr += row-size 219 # abort 220 # 221 # . prologue 222 55/push-ebp 223 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 224 # . save registers 225 51/push-ecx 226 52/push-edx 227 56/push-esi 228 # esi = table 229 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 . # copy *(ebp+8) to esi 230 # var curr/ecx: (addr handle array byte) = table->data 231 8d/copy-address 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 0xc/disp8 . # copy esi+12 to ecx 232 # var max/edx: (addr byte) = &table->data[table->write] 233 8b/copy 0/mod/indirect 6/rm32/esi . . . 2/r32/edx . . # copy *esi to edx 234 8d/copy-address 0/mod/indirect 4/rm32/sib 1/base/ecx 2/index/edx . 2/r32/edx . . # copy ecx+edx to edx 235 $get-slice:search-loop: 236 # if (curr >= max) abort 237 39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx 238 73/jump-if-addr>= $get-slice:abort/disp8 239 # var c/eax: (addr array byte) = lookup(*curr) 240 # . . push args 241 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 4/disp8 . # push *(ecx+4) 242 ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . . # push *ecx 243 # . . call 244 e8/call lookup/disp32 245 # . . discard args 246 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 247 # if (slice-equal?(key, c)) return curr+8 248 # . eax = slice-equal?(key, c) 249 # . . push args 250 50/push-eax 251 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) 252 # . . call 253 e8/call slice-equal?/disp32 254 # . . discard args 255 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 256 # . if (eax != false) return eax = curr+8 257 3d/compare-eax-and 0/imm32/false 258 74/jump-if-= $get-slice:mismatch/disp8 259 8d/copy-address 1/mod/*+disp8 1/rm32/ecx . . . 0/r32/eax 8/disp8 . # copy ecx+8 to eax 260 eb/jump $get-slice:end/disp8 261 $get-slice:mismatch: 262 # curr += row-size 263 03/add 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 0x10/disp8 . # add *(ebp+16) to ecx 264 # loop 265 eb/jump $get-slice:search-loop/disp8 266 $get-slice:end: 267 # . restore registers 268 5e/pop-to-esi 269 5a/pop-to-edx 270 59/pop-to-ecx 271 # . epilogue 272 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 273 5d/pop-to-ebp 274 c3/return 275 276 $get-slice:abort: 277 # . _write(2/stderr, abort-message-prefix) 278 # . . push args 279 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x14/disp8 . # push *(ebp+20) 280 68/push 2/imm32/stderr 281 # . . call 282 e8/call _write/disp32 283 # . . discard args 284 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 285 # . _write(2/stderr, error) 286 # . . push args 287 68/push ": get-slice: key not found: "/imm32 288 68/push 2/imm32/stderr 289 # . . call 290 e8/call _write/disp32 291 # . . discard args 292 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 293 # . write-slice-buffered(Stderr, key) 294 # . . push args 295 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) 296 68/push Stderr/imm32 297 # . . call 298 e8/call write-slice-buffered/disp32 299 # . . discard args 300 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 301 # . flush(Stderr) 302 # . . push args 303 68/push Stderr/imm32 304 # . . call 305 e8/call flush/disp32 306 # . . discard args 307 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 308 # . _write(2/stderr, "\n") 309 # . . push args 310 68/push Newline/imm32 311 68/push 2/imm32/stderr 312 # . . call 313 e8/call _write/disp32 314 # . . discard args 315 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 316 # . syscall(exit, 1) 317 bb/copy-to-ebx 1/imm32 318 e8/call syscall_exit/disp32 319 # never gets here 320 321 test-get-slice: 322 # . prologue 323 55/push-ebp 324 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 325 # - setup: create a table with a couple of keys 326 # var table/ecx: (stream {string, number} 24) # 2 rows * 12 bytes/row 327 81 5/subop/subtract 3/mod/direct 4/rm32/esp . . . . . 0x18/imm32 # subtract from esp 328 68/push 0x18/imm32/size 329 68/push 0/imm32/read 330 68/push 0/imm32/write 331 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 332 # insert(table, "code", 12 bytes/row, Heap) 333 # . . push args 334 68/push Heap/imm32 335 68/push 0xc/imm32/row-size 336 68/push "code"/imm32 337 51/push-ecx 338 # . . call 339 e8/call get-or-insert/disp32 340 # . . discard args 341 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp 342 # insert(table, "data", 12 bytes/row, Heap) 343 # . . push args 344 68/push Heap/imm32 345 68/push 0xc/imm32/row-size 346 68/push "data"/imm32 347 51/push-ecx 348 # . . call 349 e8/call get-or-insert/disp32 350 # . . discard args 351 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp 352 $test-get-slice:check1: 353 # (eax..edx) = "code" 354 b8/copy-to-eax "code"/imm32 355 8b/copy 0/mod/indirect 0/rm32/eax . . . 2/r32/edx . . # copy *eax to edx 356 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 2/index/edx . 2/r32/edx 4/disp8 . # copy eax+edx+4 to edx 357 05/add-to-eax 4/imm32 358 # var slice/edx: slice = {eax, edx} 359 52/push-edx 360 50/push-eax 361 89/copy 3/mod/direct 2/rm32/edx . . . 4/r32/esp . . # copy esp to edx 362 # eax = get-slice(table, "code", 12 bytes/row) 363 # . . push args 364 68/push 0xc/imm32/row-size 365 52/push-edx 366 51/push-ecx 367 # . . call 368 e8/call get-slice/disp32 369 # . . discard args 370 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 371 # check-ints-equal(eax - table->data, 8, msg) # first row's value slot returned 372 # . check-ints-equal(eax - table, 20, msg) 373 # . . push args 374 68/push "F - test-get-slice/0"/imm32 375 68/push 0x14/imm32 376 29/subtract 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . . # subtract ecx from eax 377 50/push-eax 378 # . . call 379 e8/call check-ints-equal/disp32 380 # . . discard args 381 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 382 $test-get-slice:check2: 383 # (eax..edx) = "data" 384 b8/copy-to-eax "data"/imm32 385 8b/copy 0/mod/indirect 0/rm32/eax . . . 2/r32/edx . . # copy *eax to edx 386 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 2/index/edx . 2/r32/edx 4/disp8 . # copy eax+edx+4 to edx 387 05/add-to-eax 4/imm32 388 # var slice/edx: slice = {eax, edx} 389 52/push-edx 390 50/push-eax 391 89/copy 3/mod/direct 2/rm32/edx . . . 4/r32/esp . . # copy esp to edx 392 # eax = get-slice(table, "data" slice, 12 bytes/row) 393 # . . push args 394 68/push 0xc/imm32/row-size 395 52/push-edx 396 51/push-ecx 397 # . . call 398 e8/call get-slice/disp32 399 # . . discard args 400 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 401 # check-ints-equal(eax - table->data, 20, msg) 402 # . check-ints-equal(eax - table, 32, msg) 403 # . . push args 404 68/push "F - test-get-slice/1"/imm32 405 68/push 0x20/imm32 406 29/subtract 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . . # subtract ecx from eax 407 50/push-eax 408 # . . call 409 e8/call check-ints-equal/disp32 410 # . . discard args 411 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 412 $test-get-slice:end: 413 # . epilogue 414 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 415 5d/pop-to-ebp 416 c3/return 417 418 # if no row is found, save 'key' to the next available row 419 # if there are no rows free, abort 420 # return the address of the value 421 get-or-insert: # table: (addr stream {(handle array byte), T}), key: (addr array byte), row-size: int, ad: (addr allocation-descriptor) -> result/eax: (addr T) 422 # pseudocode: 423 # curr = table->data 424 # max = &table->data[table->write] 425 # while curr < max 426 # var c: (addr array byte) = lookup(*curr) 427 # if string-equal?(key, c) 428 # return curr+8 429 # curr += row-size 430 # if table->write >= table->size 431 # abort 432 # zero-out(max, row-size) 433 # copy-array(ad, key, max) 434 # table->write += row-size 435 # return max+8 436 # 437 # . prologue 438 55/push-ebp 439 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 440 # . save registers 441 51/push-ecx 442 52/push-edx 443 56/push-esi 444 # esi = table 445 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 . # copy *(ebp+8) to esi 446 # var curr/ecx: (addr handle array byte) = table->data 447 8d/copy-address 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 0xc/disp8 . # copy esi+12 to ecx 448 # var max/edx: (addr byte) = &table->data[table->write] 449 8b/copy 0/mod/indirect 6/rm32/esi . . . 2/r32/edx . . # copy *esi to edx 450 8d/copy-address 0/mod/indirect 4/rm32/sib 1/base/ecx 2/index/edx . 2/r32/edx . . # copy ecx+edx to edx 451 $get-or-insert:search-loop: 452 # if (curr >= max) break 453 39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx 454 73/jump-if-addr>= $get-or-insert:not-found/disp8 455 # var c/eax: (addr array byte) = lookup(*curr) 456 # . . push args 457 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 4/disp8 . # push *(ecx+4) 458 ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . . # push *ecx 459 # . . call 460 e8/call lookup/disp32 461 # . . discard args 462 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 463 # if (string-equal?(key, c)) return curr+8 464 # . eax = string-equal?(key, c) 465 # . . push args 466 50/push-eax 467 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) 468 # . . call 469 e8/call string-equal?/disp32 470 # . . discard args 471 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 472 # . if (eax != false) return eax = curr+8 473 3d/compare-eax-and 0/imm32/false 474 74/jump-if-= $get-or-insert:mismatch/disp8 475 8d/copy-address 1/mod/*+disp8 1/rm32/ecx . . . 0/r32/eax 8/disp8 . # copy ecx+8 to eax 476 eb/jump $get-or-insert:end/disp8 477 $get-or-insert:mismatch: 478 # curr += row-size 479 03/add 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 0x10/disp8 . # add *(ebp+16) to ecx 480 # loop 481 eb/jump $get-or-insert:search-loop/disp8 482 $get-or-insert:not-found: 483 # if (table->write >= table->size) abort 484 8b/copy 0/mod/indirect 6/rm32/esi . . . 1/r32/ecx . . # copy *esi to ecx 485 3b/compare 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 8/disp8 . # compare ecx with *(esi+8) 486 73/jump-if-addr>= $get-or-insert:abort/disp8 487 # zero-out(max, row-size) 488 # . . push args 489 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x10/disp8 . # push *(ebp+16) 490 52/push-edx 491 # . . call 492 e8/call zero-out/disp32 493 # . . discard args 494 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 495 # copy-array(ad, key, max) 496 # . . push args 497 52/push-edx 498 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) 499 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x14/disp8 . # push *(ebp+20) 500 # . . call 501 e8/call copy-array/disp32 502 # . . discard args 503 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 504 # table->write += row-size 505 # . eax = row-size 506 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 0x10/disp8 . # copy *(ebp+16) to eax 507 # . table->write += eax 508 01/add 0/mod/indirect 6/rm32/esi . . . 0/r32/eax . . # add eax to *esi 509 # return max+8 510 # . eax = max 511 89/copy 3/mod/direct 0/rm32/eax . . . 2/r32/edx . . # copy edx to eax 512 # . eax += 8 513 05/add-to-eax 8/imm32 514 $get-or-insert:end: 515 # . restore registers 516 5e/pop-to-esi 517 5a/pop-to-edx 518 59/pop-to-ecx 519 # . epilogue 520 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 521 5d/pop-to-ebp 522 c3/return 523 524 $get-or-insert:abort: 525 # . _write(2/stderr, error) 526 # . . push args 527 68/push "get-or-insert: table is full\n"/imm32 528 68/push 2/imm32/stderr 529 # . . call 530 e8/call _write/disp32 531 # . . discard args 532 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 533 # . syscall(exit, 1) 534 bb/copy-to-ebx 1/imm32 535 e8/call syscall_exit/disp32 536 # never gets here 537 538 test-get-or-insert: 539 # . prologue 540 55/push-ebp 541 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 542 # var table/ecx: (stream {(handle array byte), number} 24) # 2 rows * 12 bytes/row 543 81 5/subop/subtract 3/mod/direct 4/rm32/esp . . . . . 0x18/imm32 # subtract from esp 544 68/push 0x18/imm32/size 545 68/push 0/imm32/read 546 68/push 0/imm32/write 547 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 548 $test-get-or-insert:first-call: 549 # - start with an empty table, insert one key, verify that it was inserted 550 # eax = get-or-insert(table, "code", 12 bytes/row, Heap) 551 # . . push args 552 68/push Heap/imm32 553 68/push 0xc/imm32/row-size 554 68/push "code"/imm32 555 51/push-ecx 556 # . . call 557 e8/call get-or-insert/disp32 558 # . . discard args 559 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp 560 # check-ints-equal(eax - table->data, 8, msg) # first row's value slot returned 561 # . check-ints-equal(eax - table, 20, msg) 562 # . . push args 563 68/push "F - test-get-or-insert/0"/imm32 564 68/push 0x14/imm32 565 29/subtract 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . . # subtract ecx from eax 566 50/push-eax 567 # . . call 568 e8/call check-ints-equal/disp32 569 # . . discard args 570 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 571 # check-ints-equal(table->write, row-size = 12, msg) 572 # . . push args 573 68/push "F - test-get-or-insert/1"/imm32 574 68/push 0xc/imm32/row-size 575 ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . . # push *ecx 576 # . . call 577 e8/call check-ints-equal/disp32 578 # . . discard args 579 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 580 # var curr-addr/eax: (addr array byte) = lookup(table->data) 581 # . . push args 582 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 0x10/disp8 . # push *(ecx+16) 583 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 0xc/disp8 . # push *(ecx+12) 584 # . . call 585 e8/call lookup/disp32 586 # . . discard args 587 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 588 # check-strings-equal(curr-addr, "code", msg) 589 # . . push args 590 68/push "F - test-get-or-insert/2"/imm32 591 68/push "code"/imm32 592 50/push-eax 593 # . . call 594 e8/call check-strings-equal/disp32 595 # . . discard args 596 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 597 $test-get-or-insert:second-call: 598 # - insert the same key again, verify that it was reused 599 # eax = get-or-insert(table, "code", 12 bytes/row, Heap) 600 # . . push args 601 68/push Heap/imm32 602 68/push 0xc/imm32/row-size 603 68/push "code"/imm32 604 51/push-ecx 605 # . . call 606 e8/call get-or-insert/disp32 607 # . . discard args 608 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp 609 # check-ints-equal(eax - table->data, 8, msg) 610 # . check-ints-equal(eax - table, 20, msg) 611 # . . push args 612 68/push "F - test-get-or-insert/3"/imm32 613 68/push 0x14/imm32 614 29/subtract 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . . # subtract ecx from eax 615 50/push-eax 616 # . . call 617 e8/call check-ints-equal/disp32 618 # . . discard args 619 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 620 # no new row inserted 621 # . check-ints-equal(table->write, row-size = 12, msg) 622 # . . push args 623 68/push "F - test-get-or-insert/4"/imm32 624 68/push 0xc/imm32/row-size 625 ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . . # push *ecx 626 # . . call 627 e8/call check-ints-equal/disp32 628 # . . discard args 629 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 630 # curr-addr = lookup(table->data) 631 # . . push args 632 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 0x10/disp8 . # push *(ecx+16) 633 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 0xc/disp8 . # push *(ecx+12) 634 # . . call 635 e8/call lookup/disp32 636 # . . discard args 637 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 638 # check-strings-equal(curr-addr, "code", msg) 639 # . . push args 640 68/push "F - test-get-or-insert/5"/imm32 641 68/push "code"/imm32 642 50/push-eax 643 # . . call 644 e8/call check-strings-equal/disp32 645 # . . discard args 646 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 647 $test-get-or-insert:third-call: 648 # - insert a new key, verify that it was inserted 649 # eax = get-or-insert(table, "data", 12 bytes/row, Heap) 650 # . . push args 651 68/push Heap/imm32 652 68/push 0xc/imm32/row-size 653 68/push "data"/imm32 654 51/push-ecx 655 # . . call 656 e8/call get-or-insert/disp32 657 # . . discard args 658 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp 659 # table gets a new row 660 # check-ints-equal(eax - table->data, 20, msg) # second row's value slot returned 661 # . check-ints-equal(eax - table, 32, msg) 662 # . . push args 663 68/push "F - test-get-or-insert/6"/imm32 664 68/push 0x20/imm32 665 29/subtract 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . . # subtract ecx from eax 666 50/push-eax 667 # . . call 668 e8/call check-ints-equal/disp32 669 # . . discard args 670 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 671 # check-ints-equal(table->write, 2 rows = 24, msg) 672 # . . push args 673 68/push "F - test-get-or-insert/7"/imm32 674 68/push 0x18/imm32/two-rows 675 ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . . # push *ecx 676 # . . call 677 e8/call check-ints-equal/disp32 678 # . . discard args 679 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 680 # curr-addr = lookup(table->data+12) 681 # . . push args 682 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 0x1c/disp8 . # push *(ecx+28) 683 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 0x18/disp8 . # push *(ecx+24) 684 # . . call 685 e8/call lookup/disp32 686 # . . discard args 687 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 688 # check-strings-equal(curr-addr, "data", msg) 689 # . . push args 690 68/push "F - test-get-or-insert/8"/imm32 691 68/push "data"/imm32 692 50/push-eax 693 # . . call 694 e8/call check-strings-equal/disp32 695 # . . discard args 696 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 697 $test-get-or-insert:end: 698 # . epilogue 699 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 700 5d/pop-to-ebp 701 c3/return 702 703 # if no row is found, save 'key' to the next available row 704 # if there are no rows free, abort 705 # return the address of the value 706 get-or-insert-handle: # table: (addr stream {(handle array byte), T}), key: (handle array byte), row-size: int -> result/eax: (addr T) 707 # pseudocode: 708 # var curr: (addr handle stream) = table->data 709 # var max: (addr byte) = &table->data[table->write] 710 # var k: (addr array byte) = lookup(key) 711 # while curr < max 712 # var c: (addr array byte) = lookup(*curr) 713 # if string-equal?(k, c) 714 # return curr+8 715 # curr += row-size 716 # if table->write >= table->size 717 # abort 718 # *max = key 719 # table->write += row-size 720 # return max+8 721 # 722 # . prologue 723 55/push-ebp 724 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 725 # . save registers 726 51/push-ecx 727 52/push-edx 728 53/push-ebx 729 56/push-esi 730 # esi = table 731 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 . # copy *(ebp+8) to esi 732 # var k/ebx: (addr array byte) = lookup(key) 733 # . eax = lookup(key) 734 # . . push args 735 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x10/disp8 . # push *(ebp+16) 736 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) 737 # . . call 738 e8/call lookup/disp32 739 # . . discard args 740 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 741 # . ebx = eax 742 89/copy 3/mod/direct 3/rm32/ebx . . . 0/r32/eax . . # copy eax to ebx 743 # var curr/ecx: (addr handle array byte) = table->data 744 8d/copy-address 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 0xc/disp8 . # copy esi+12 to ecx 745 # var max/edx: (addr byte) = &table->data[table->write] 746 8b/copy 0/mod/indirect 6/rm32/esi . . . 2/r32/edx . . # copy *esi to edx 747 8d/copy-address 0/mod/indirect 4/rm32/sib 1/base/ecx 2/index/edx . 2/r32/edx . . # copy ecx+edx to edx 748 $get-or-insert-handle:search-loop: 749 # if (curr >= max) break 750 39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx 751 73/jump-if-addr>= $get-or-insert-handle:not-found/disp8 752 # var c/eax: (addr array byte) = lookup(*curr) 753 # . . push args 754 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 4/disp8 . # push *(ecx+4) 755 ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . . # push *ecx 756 # . . call 757 e8/call lookup/disp32 758 # . . discard args 759 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 760 # if (string-equal?(k, c)) return curr+8 761 # . eax = string-equal?(k, c) 762 # . . push args 763 50/push-eax 764 53/push-ebx 765 # . . call 766 e8/call string-equal?/disp32 767 # . . discard args 768 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 769 # . if (eax != false) return eax = curr+8 770 3d/compare-eax-and 0/imm32/false 771 74/jump-if-= $get-or-insert-handle:mismatch/disp8 772 8d/copy-address 1/mod/*+disp8 1/rm32/ecx . . . 0/r32/eax 8/disp8 . # copy ecx+8 to eax 773 eb/jump $get-or-insert-handle:end/disp8 774 $get-or-insert-handle:mismatch: 775 # curr += row-size 776 03/add 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 0x14/disp8 . # add *(ebp+20) to ecx 777 # loop 778 eb/jump $get-or-insert-handle:search-loop/disp8 779 $get-or-insert-handle:not-found: 780 # if (table->write >= table->size) abort 781 8b/copy 0/mod/indirect 6/rm32/esi . . . 1/r32/ecx . . # copy *esi to ecx 782 3b/compare 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 8/disp8 . # compare ecx with *(esi+8) 783 73/jump-if-addr>= $get-or-insert-handle:abort/disp8 784 # table->write += row-size 785 # . eax = row-size 786 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 0x14/disp8 . # copy *(ebp+20) to eax 787 # . table->write += eax 788 01/add 0/mod/indirect 6/rm32/esi . . . 0/r32/eax . . # add eax to *esi 789 # *max = key 790 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 0xc/disp8 . # copy *(ebp+12) to eax 791 89/copy 0/mod/indirect 2/rm32/edx . . . 0/r32/eax . . # copy eax to *edx 792 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 0x10/disp8 . # copy *(ebp+16) to eax 793 89/copy 1/mod/*+disp8 2/rm32/edx . . . 0/r32/eax 4/disp8 . # copy eax to *(edx+4) 794 # return max+8 795 # . eax = max 796 89/copy 3/mod/direct 0/rm32/eax . . . 2/r32/edx . . # copy edx to eax 797 # . eax += 8 798 05/add-to-eax 8/imm32 799 $get-or-insert-handle:end: 800 # . restore registers 801 5e/pop-to-esi 802 5b/pop-to-ebx 803 5a/pop-to-edx 804 59/pop-to-ecx 805 # . epilogue 806 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 807 5d/pop-to-ebp 808 c3/return 809 810 $get-or-insert-handle:abort: 811 # . _write(2/stderr, error) 812 # . . push args 813 68/push "get-or-insert-handle: table is full\n"/imm32 814 68/push 2/imm32/stderr 815 # . . call 816 e8/call _write/disp32 817 # . . discard args 818 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 819 # . syscall(exit, 1) 820 bb/copy-to-ebx 1/imm32 821 e8/call syscall_exit/disp32 822 # never gets here 823 824 test-get-or-insert-handle: 825 # . prologue 826 55/push-ebp 827 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 828 # var table/ecx: (stream {(handle array byte), number} 24) # 2 rows * 12 bytes/row 829 81 5/subop/subtract 3/mod/direct 4/rm32/esp . . . . . 0x18/imm32 # subtract from esp 830 68/push 0x18/imm32/size 831 68/push 0/imm32/read 832 68/push 0/imm32/write 833 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 834 # var h/edx: (handle array byte) 835 68/push 0/imm32 836 68/push 0/imm32 837 89/copy 3/mod/direct 2/rm32/edx . . . 4/r32/esp . . # copy esp to edx 838 $test-get-or-insert-handle:first-call: 839 # - start with an empty table, insert one key, verify that it was inserted 840 # copy-array(Heap, "code", h) 841 # . . push args 842 52/push-edx 843 68/push "code"/imm32 844 68/push Heap/imm32 845 # . . call 846 e8/call copy-array/disp32 847 # . . discard args 848 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 849 # eax = get-or-insert-handle(table, h, 12 bytes/row) 850 # . . push args 851 68/push 0xc/imm32/row-size 852 ff 6/subop/push 1/mod/*+disp8 2/rm32/edx . . . . 4/disp8 . # push *(edx+4) 853 ff 6/subop/push 0/mod/indirect 2/rm32/edx . . . . . . # push *edx 854 51/push-ecx 855 # . . call 856 e8/call get-or-insert-handle/disp32 857 # . . discard args 858 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp 859 # check-ints-equal(eax - table->data, 8, msg) # first row's value slot returned 860 # . check-ints-equal(eax - table, 20, msg) 861 # . . push args 862 68/push "F - test-get-or-insert-handle/0"/imm32 863 68/push 0x14/imm32 864 29/subtract 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . . # subtract ecx from eax 865 50/push-eax 866 # . . call 867 e8/call check-ints-equal/disp32 868 # . . discard args 869 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 870 # check-ints-equal(table->write, row-size = 12, msg) 871 # . . push args 872 68/push "F - test-get-or-insert-handle/1"/imm32 873 68/push 0xc/imm32/row-size 874 ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . . # push *ecx 875 # . . call 876 e8/call check-ints-equal/disp32 877 # . . discard args 878 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 879 # var curr-addr/eax: (addr array byte) = lookup(table->data) 880 # . . push args 881 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 0x10/disp8 . # push *(ecx+16) 882 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 0xc/disp8 . # push *(ecx+12) 883 # . . call 884 e8/call lookup/disp32 885 # . . discard args 886 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 887 # check-strings-equal(curr-addr, "code", msg) 888 # . . push args 889 68/push "F - test-get-or-insert-handle/2"/imm32 890 68/push "code"/imm32 891 50/push-eax 892 # . . call 893 e8/call check-strings-equal/disp32 894 # . . discard args 895 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 896 $test-get-or-insert-handle:second-call: 897 # - insert the same key again, verify that it was reused 898 # copy-array(Heap, "code", h) 899 # . . push args 900 52/push-edx 901 68/push "code"/imm32 902 68/push Heap/imm32 903 # . . call 904 e8/call copy-array/disp32 905 # . . discard args 906 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 907 # eax = get-or-insert-handle(table, h, 12 bytes/row) 908 # . . push args 909 68/push 0xc/imm32/row-size 910 ff 6/subop/push 1/mod/*+disp8 2/rm32/edx . . . . 4/disp8 . # push *(edx+4) 911 ff 6/subop/push 0/mod/indirect 2/rm32/edx . . . . . . # push *edx 912 51/push-ecx 913 # . . call 914 e8/call get-or-insert-handle/disp32 915 # . . discard args 916 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp 917 # check-ints-equal(eax - table->data, 8, msg) 918 # . check-ints-equal(eax - table, 20, msg) 919 # . . push args 920 68/push "F - test-get-or-insert-handle/3"/imm32 921 68/push 0x14/imm32 922 29/subtract 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . . # subtract ecx from eax 923 50/push-eax 924 # . . call 925 e8/call check-ints-equal/disp32 926 # . . discard args 927 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 928 # no new row inserted 929 # . check-ints-equal(table->write, row-size = 12, msg) 930 # . . push args 931 68/push "F - test-get-or-insert-handle/4"/imm32 932 68/push 0xc/imm32/row-size 933 ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . . # push *ecx 934 # . . call 935 e8/call check-ints-equal/disp32 936 # . . discard args 937 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 938 # curr-addr = lookup(table->data) 939 # . . push args 940 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 0x10/disp8 . # push *(ecx+16) 941 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 0xc/disp8 . # push *(ecx+12) 942 # . . call 943 e8/call lookup/disp32 944 # . . discard args 945 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 946 # check-strings-equal(curr-addr, "code", msg) 947 # . . push args 948 68/push "F - test-get-or-insert-handle/5"/imm32 949 68/push "code"/imm32 950 50/push-eax 951 # . . call 952 e8/call check-strings-equal/disp32 953 # . . discard args 954 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 955 $test-get-or-insert-handle:third-call: 956 # - insert a new key, verify that it was inserted 957 # copy-array(Heap, "data", h) 958 # . . push args 959 52/push-edx 960 68/push "data"/imm32 961 68/push Heap/imm32 962 # . . call 963 e8/call copy-array/disp32 964 # . . discard args 965 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 966 # eax = get-or-insert-handle(table, h, 12 bytes/row) 967 # . . push args 968 68/push 0xc/imm32/row-size 969 ff 6/subop/push 1/mod/*+disp8 2/rm32/edx . . . . 4/disp8 . # push *(edx+4) 970 ff 6/subop/push 0/mod/indirect 2/rm32/edx . . . . . . # push *edx 971 51/push-ecx 972 # . . call 973 e8/call get-or-insert-handle/disp32 974 # . . discard args 975 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp 976 # table gets a new row 977 # check-ints-equal(eax - table->data, 20, msg) # second row's value slot returned 978 # . check-ints-equal(eax - table, 32, msg) 979 # . . push args 980 68/push "F - test-get-or-insert-handle/6"/imm32 981 68/push 0x20/imm32 982 29/subtract 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . . # subtract ecx from eax 983 50/push-eax 984 # . . call 985 e8/call check-ints-equal/disp32 986 # . . discard args 987 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 988 # check-ints-equal(table->write, 2 rows = 24, msg) 989 # . . push args 990 68/push "F - test-get-or-insert-handle/7"/imm32 991 68/push 0x18/imm32/two-rows 992 ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . . # push *ecx 993 # . . call 994 e8/call check-ints-equal/disp32 995 # . . discard args 996 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 997 # curr-addr = lookup(table->data+12) 998 # . . push args 999 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 0x1c/disp8 . # push *(ecx+28) 1000 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 0x18/disp8 . # push *(ecx+24) 1001 # . . call 1002 e8/call lookup/disp32 1003 # . . discard args 1004 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1005 # check-strings-equal(curr-addr, "data", msg) 1006 # . . push args 1007 68/push "F - test-get-or-insert-handle/8"/imm32 1008 68/push "data"/imm32 1009 50/push-eax 1010 # . . call 1011 e8/call check-strings-equal/disp32 1012 # . . discard args 1013 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1014 $test-get-or-insert-handle:end: 1015 # . epilogue 1016 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 1017 5d/pop-to-ebp 1018 c3/return 1019 1020 # if no row is found, save 'key' in the next available row 1021 # if there are no rows free, abort 1022 get-or-insert-slice: # table: (addr stream {(handle array byte), T}), key: (addr slice), row-size: int, ad: (addr allocation-descriptor) -> result/eax: (addr T) 1023 # pseudocode: 1024 # curr = table->data 1025 # max = &table->data[table->write] 1026 # while curr < max 1027 # var c: (addr array byte) = lookup(*curr) 1028 # if slice-equal?(key, *curr) 1029 # return curr+8 1030 # curr += row-size 1031 # if table->write >= table->size 1032 # abort 1033 # zero-out(max, row-size) 1034 # slice-to-string(ad, key, max) 1035 # table->write += row-size 1036 # return max+8 1037 # 1038 # . prologue 1039 55/push-ebp 1040 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 1041 # . save registers 1042 51/push-ecx 1043 52/push-edx 1044 56/push-esi 1045 # esi = table 1046 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 . # copy *(ebp+8) to esi 1047 # var curr/ecx: (addr handle array byte) = table->data 1048 8d/copy-address 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 0xc/disp8 . # copy esi+12 to ecx 1049 # var max/edx: (addr byte) = &table->data[table->write] 1050 8b/copy 0/mod/indirect 6/rm32/esi . . . 2/r32/edx . . # copy *esi to edx 1051 8d/copy-address 0/mod/indirect 4/rm32/sib 1/base/ecx 2/index/edx . 2/r32/edx . . # copy ecx+edx to edx 1052 $get-or-insert-slice:search-loop: 1053 # if (curr >= max) break 1054 39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx 1055 73/jump-if-addr>= $get-or-insert-slice:not-found/disp8 1056 # var c/eax: (addr array byte) = lookup(*curr) 1057 # . . push args 1058 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 4/disp8 . # push *(ecx+4) 1059 ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . . # push *ecx 1060 # . . call 1061 e8/call lookup/disp32 1062 # . . discard args 1063 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1064 # if (slice-equal?(key, c)) return curr+4 1065 # . eax = slice-equal?(key, c) 1066 # . . push args 1067 50/push-eax 1068 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) 1069 # . . call 1070 e8/call slice-equal?/disp32 1071 # . . discard args 1072 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1073 # . if (eax != false) return eax = curr+8 1074 3d/compare-eax-and 0/imm32/false 1075 74/jump-if-= $get-or-insert-slice:mismatch/disp8 1076 8d/copy-address 1/mod/*+disp8 1/rm32/ecx . . . 0/r32/eax 8/disp8 . # copy ecx+8 to eax 1077 eb/jump $get-or-insert-slice:end/disp8 1078 $get-or-insert-slice:mismatch: 1079 # curr += row-size 1080 03/add 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 0x10/disp8 . # add *(ebp+16) to ecx 1081 # loop 1082 eb/jump $get-or-insert-slice:search-loop/disp8 1083 $get-or-insert-slice:not-found: 1084 # result/eax = 0 1085 31/xor 3/mod/direct 0/rm32/eax . . . 0/r32/eax . . # clear eax 1086 # if (table->write >= table->size) abort 1087 8b/copy 0/mod/indirect 6/rm32/esi . . . 1/r32/ecx . . # copy *esi to ecx 1088 3b/compare 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 8/disp8 . # compare ecx with *(esi+8) 1089 7d/jump-if->= $get-or-insert-slice:abort/disp8 1090 # zero-out(max, row-size) 1091 # . . push args 1092 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x10/disp8 . # push *(ebp+16) 1093 52/push-edx 1094 # . . call 1095 e8/call zero-out/disp32 1096 # . . discard args 1097 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1098 # slice-to-string(ad, key, max) 1099 # . . push args 1100 52/push-edx 1101 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) 1102 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x14/disp8 . # push *(ebp+20) 1103 # . . call 1104 e8/call slice-to-string/disp32 1105 # . . discard args 1106 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1107 # table->write += row-size 1108 # . eax = row-size 1109 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 0x10/disp8 . # copy *(ebp+16) to eax 1110 # . table->write += eax 1111 01/add 0/mod/indirect 6/rm32/esi . . . 0/r32/eax . . # add eax to *esi 1112 # return max+8 1113 # . eax = max 1114 89/copy 3/mod/direct 0/rm32/eax . . . 2/r32/edx . . # copy edx to eax 1115 # . eax += 8 1116 05/add-to-eax 8/imm32 1117 $get-or-insert-slice:end: 1118 # . restore registers 1119 5e/pop-to-esi 1120 5a/pop-to-edx 1121 59/pop-to-ecx 1122 # . epilogue 1123 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 1124 5d/pop-to-ebp 1125 c3/return 1126 1127 $get-or-insert-slice:abort: 1128 # . _write(2/stderr, error) 1129 # . . push args 1130 68/push "get-or-insert-slice: table is full\n"/imm32 1131 68/push 2/imm32/stderr 1132 # . . call 1133 e8/call _write/disp32 1134 # . . discard args 1135 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1136 # . syscall(exit, 1) 1137 bb/copy-to-ebx 1/imm32 1138 e8/call syscall_exit/disp32 1139 # never gets here 1140 1141 test-get-or-insert-slice: 1142 # . prologue 1143 55/push-ebp 1144 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 1145 # var table/ecx: (stream {string, number} 24) # 2 rows * 12 bytes/row 1146 81 5/subop/subtract 3/mod/direct 4/rm32/esp . . . . . 0x18/imm32 # subtract from esp 1147 68/push 0x18/imm32/size 1148 68/push 0/imm32/read 1149 68/push 0/imm32/write 1150 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 1151 # (eax..edx) = "code" 1152 b8/copy-to-eax "code"/imm32 1153 8b/copy 0/mod/indirect 0/rm32/eax . . . 2/r32/edx . . # copy *eax to edx 1154 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 2/index/edx . 2/r32/edx 4/disp8 . # copy eax+edx+4 to edx 1155 05/add-to-eax 4/imm32 1156 # var slice/edx: slice = {eax, edx} 1157 52/push-edx 1158 50/push-eax 1159 89/copy 3/mod/direct 2/rm32/edx . . . 4/r32/esp . . # copy esp to edx 1160 $test-get-or-insert-slice:first-call: 1161 # - start with an empty table, insert one key, verify that it was inserted 1162 # eax = get-or-insert-slice(table, "code" slice, 12 bytes/row, Heap) 1163 # . . push args 1164 68/push Heap/imm32 1165 68/push 0xc/imm32/row-size 1166 52/push-edx 1167 51/push-ecx 1168 # . . call 1169 e8/call get-or-insert-slice/disp32 1170 # . . discard args 1171 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp 1172 # check-ints-equal(eax - table->data, 8, msg) # first row's value slot returned 1173 # . check-ints-equal(eax - table, 20, msg) 1174 # . . push args 1175 68/push "F - test-get-or-insert-slice/0"/imm32 1176 68/push 0x14/imm32 1177 29/subtract 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . . # subtract ecx from eax 1178 50/push-eax 1179 # . . call 1180 e8/call check-ints-equal/disp32 1181 # . . discard args 1182 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1183 # check-ints-equal(table->write, row-size = 12, msg) 1184 # . . push args 1185 68/push "F - test-get-or-insert-slice/1"/imm32 1186 68/push 0xc/imm32/row-size 1187 ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . . # push *ecx 1188 # . . call 1189 e8/call check-ints-equal/disp32 1190 # . . discard args 1191 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1192 # var curr-addr/eax: (addr array byte) = lookup(table->data) 1193 # . . push args 1194 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 0x10/disp8 . # push *(ecx+16) 1195 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 0xc/disp8 . # push *(ecx+12) 1196 # . . call 1197 e8/call lookup/disp32 1198 # . . discard args 1199 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1200 # check-strings-equal(curr-addr, "code", msg) 1201 # . . push args 1202 68/push "F - test-get-or-insert-slice/2"/imm32 1203 68/push "code"/imm32 1204 50/push-eax 1205 # . . call 1206 e8/call check-strings-equal/disp32 1207 # . . discard args 1208 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1209 $test-get-or-insert-slice:second-call: 1210 # - insert the same key again, verify that it was reused 1211 # eax = get-or-insert-slice(table, "code" slice, 12 bytes/row) 1212 # . . push args 1213 68/push Heap/imm32 1214 68/push 0xc/imm32/row-size 1215 52/push-edx 1216 51/push-ecx 1217 # . . call 1218 e8/call get-or-insert-slice/disp32 1219 # . . discard args 1220 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp 1221 # check-ints-equal(eax - table->data, 8, msg) 1222 # . check-ints-equal(eax - table, 20, msg) 1223 # . . push args 1224 68/push "F - test-get-or-insert-slice/3"/imm32 1225 68/push 0x14/imm32 1226 29/subtract 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . . # subtract ecx from eax 1227 50/push-eax 1228 # . . call 1229 e8/call check-ints-equal/disp32 1230 # . . discard args 1231 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1232 # no new row inserted 1233 # . check-ints-equal(table->write, row-size = 12, msg) 1234 # . . push args 1235 68/push "F - test-get-or-insert-slice/4"/imm32 1236 68/push 0xc/imm32/row-size 1237 ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . . # push *ecx 1238 # . . call 1239 e8/call check-ints-equal/disp32 1240 # . . discard args 1241 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1242 # curr-addr = lookup(table->data) 1243 # . . push args 1244 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 0x10/disp8 . # push *(ecx+16) 1245 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 0xc/disp8 . # push *(ecx+12) 1246 # . . call 1247 e8/call lookup/disp32 1248 # . . discard args 1249 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1250 # check-strings-equal(curr-addr, "code", msg) 1251 # . . push args 1252 68/push "F - test-get-or-insert-slice/5"/imm32 1253 68/push "code"/imm32 1254 50/push-eax 1255 # . . call 1256 e8/call check-strings-equal/disp32 1257 # . . discard args 1258 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1259 $test-get-or-insert-slice:third-call: 1260 # - insert a new key, verify that it was inserted 1261 # (eax..edx) = "data" 1262 b8/copy-to-eax "data"/imm32 1263 8b/copy 0/mod/indirect 0/rm32/eax . . . 2/r32/edx . . # copy *eax to edx 1264 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 2/index/edx . 2/r32/edx 4/disp8 . # copy eax+edx+4 to edx 1265 05/add-to-eax 4/imm32 1266 # var slice/edx: slice = {eax, edx} 1267 52/push-edx 1268 50/push-eax 1269 89/copy 3/mod/direct 2/rm32/edx . . . 4/r32/esp . . # copy esp to edx 1270 # eax = get-or-insert-slice(table, "data" slice, 12 bytes/row) 1271 # . . push args 1272 68/push Heap/imm32 1273 68/push 0xc/imm32/row-size 1274 52/push-edx 1275 51/push-ecx 1276 # . . call 1277 e8/call get-or-insert-slice/disp32 1278 # . . discard args 1279 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp 1280 # table gets a new row 1281 # check-ints-equal(eax - table->data, 20, msg) # second row's value slot returned 1282 # . check-ints-equal(eax - table, 32, msg) 1283 # . . push args 1284 68/push "F - test-get-or-insert-slice/6"/imm32 1285 68/push 0x20/imm32 1286 29/subtract 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . . # subtract ecx from eax 1287 50/push-eax 1288 # . . call 1289 e8/call check-ints-equal/disp32 1290 # . . discard args 1291 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1292 # check-ints-equal(table->write, 2 rows = 24, msg) 1293 # . . push args 1294 68/push "F - test-get-or-insert-slice/7"/imm32 1295 68/push 0x18/imm32/two-rows 1296 ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . . # push *ecx 1297 # . . call 1298 e8/call check-ints-equal/disp32 1299 # . . discard args 1300 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1301 # curr-addr = lookup(table->data+12) 1302 # . . push args 1303 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 0x1c/disp8 . # push *(ecx+28) 1304 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 0x18/disp8 . # push *(ecx+24) 1305 # . . call 1306 e8/call lookup/disp32 1307 # . . discard args 1308 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1309 # check-strings-equal(curr-addr, "data", msg) 1310 # . . push args 1311 68/push "F - test-get-or-insert-slice/8"/imm32 1312 68/push "data"/imm32 1313 50/push-eax 1314 # . . call 1315 e8/call check-strings-equal/disp32 1316 # . . discard args 1317 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1318 $test-get-or-insert-slice:end: 1319 # . epilogue 1320 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 1321 5d/pop-to-ebp 1322 c3/return 1323 1324 # if no row is found, stop(ed) 1325 get-or-stop: # table: (addr stream {(handle array byte), T}), key: (addr array byte), row-size: int, 1326 # abort-message-prefix: (addr array byte), err: (addr buffered-file), ed: (addr exit-descriptor) 1327 # -> result/eax: (addr T) 1328 # pseudocode: 1329 # curr = table->data 1330 # max = &table->data[table->write] 1331 # while curr < max 1332 # var c: (addr array byte) = lookup(*curr) 1333 # if string-equal?(key, c) 1334 # return curr+8 1335 # curr += row-size 1336 # write-buffered(err, msg) 1337 # stop(ed) 1338 # 1339 # . prologue 1340 55/push-ebp 1341 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 1342 # . save registers 1343 51/push-ecx 1344 52/push-edx 1345 56/push-esi 1346 # esi = table 1347 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 . # copy *(ebp+8) to esi 1348 # var curr/ecx: (addr handle array byte) = table->data 1349 8d/copy-address 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 0xc/disp8 . # copy esi+12 to ecx 1350 # var max/edx: (addr byte) = &table->data[table->write] 1351 8b/copy 0/mod/indirect 6/rm32/esi . . . 2/r32/edx . . # copy *esi to edx 1352 8d/copy-address 0/mod/indirect 4/rm32/sib 1/base/ecx 2/index/edx . 2/r32/edx . . # copy ecx+edx to edx 1353 $get-or-stop:search-loop: 1354 # if (curr >= max) stop(ed) 1355 39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx 1356 73/jump-if-addr>= $get-or-stop:stop/disp8 1357 # var c/eax: (addr array byte) = lookup(*curr) 1358 # . . push args 1359 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 4/disp8 . # push *(ecx+4) 1360 ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . . # push *ecx 1361 # . . call 1362 e8/call lookup/disp32 1363 # . . discard args 1364 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1365 # if (string-equal?(key, c)) return curr+8 1366 # . eax = string-equal?(key, c) 1367 # . . push args 1368 50/push-eax 1369 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) 1370 # . . call 1371 e8/call string-equal?/disp32 1372 # . . discard args 1373 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1374 # . if (eax != false) return eax = curr+8 1375 3d/compare-eax-and 0/imm32/false 1376 74/jump-if-= $get-or-stop:mismatch/disp8 1377 8d/copy-address 1/mod/*+disp8 1/rm32/ecx . . . 0/r32/eax 8/disp8 . # copy ecx+8 to eax 1378 eb/jump $get-or-stop:end/disp8 1379 $get-or-stop:mismatch: 1380 # curr += row-size 1381 03/add 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 0x10/disp8 . # add *(ebp+16) to ecx 1382 # loop 1383 eb/jump $get-or-stop:search-loop/disp8 1384 $get-or-stop:end: 1385 # . restore registers 1386 5e/pop-to-esi 1387 5a/pop-to-edx 1388 59/pop-to-ecx 1389 # . epilogue 1390 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 1391 5d/pop-to-ebp 1392 c3/return 1393 1394 $get-or-stop:stop: 1395 # . write-buffered(err, abort-message-prefix) 1396 # . . push args 1397 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x14/disp8 . # push *(ebp+20) 1398 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x18/disp8 . # push *(ebp+24) 1399 # . . call 1400 e8/call write-buffered/disp32 1401 # . . discard args 1402 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1403 # . write-buffered(err, error) 1404 # . . push args 1405 68/push ": get-or-stop: key not found: "/imm32 1406 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x18/disp8 . # push *(ebp+24) 1407 # . . call 1408 e8/call write-buffered/disp32 1409 # . . discard args 1410 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1411 # . write-buffered(err, key) 1412 # . . push args 1413 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) 1414 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x18/disp8 . # push *(ebp+24) 1415 # . . call 1416 e8/call write-buffered/disp32 1417 # . . discard args 1418 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1419 # . write-buffered(err, "\n") 1420 # . . push args 1421 68/push Newline/imm32 1422 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x18/disp8 . # push *(ebp+24) 1423 # . . call 1424 e8/call write-buffered/disp32 1425 # . . discard args 1426 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1427 # . stop(ed, 1) 1428 # . . push args 1429 68/push 1/imm32 1430 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x1c/disp8 . # push *(ebp+28) 1431 # . . call 1432 e8/call stop/disp32 1433 # never gets here 1434 $get-or-stop:terminus: 1435 # . . discard args 1436 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1437 # syscall(exit, 1) 1438 bb/copy-to-ebx 1/imm32 1439 e8/call syscall_exit/disp32 1440 1441 test-get-or-stop: 1442 # This test uses exit-descriptors. Use ebp for setting up local variables. 1443 # . prologue 1444 55/push-ebp 1445 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 1446 # setup 1447 # . clear-stream(_test-error-stream) 1448 # . . push args 1449 68/push _test-error-stream/imm32 1450 # . . call 1451 e8/call clear-stream/disp32 1452 # . . discard args 1453 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1454 # . clear-stream($_test-error-buffered-file->buffer) 1455 # . . push args 1456 68/push $_test-error-buffered-file->buffer/imm32 1457 # . . call 1458 e8/call clear-stream/disp32 1459 # . . discard args 1460 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1461 # var table/ecx: (stream {string, number} 24) # 2 rows * 12 bytes/row 1462 81 5/subop/subtract 3/mod/direct 4/rm32/esp . . . . . 0x18/imm32 # subtract from esp 1463 68/push 0x18/imm32/size 1464 68/push 0/imm32/read 1465 68/push 0/imm32/write 1466 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 1467 # var ed/edx: exit-descriptor 1468 68/push 0/imm32 1469 68/push 0/imm32 1470 89/copy 3/mod/direct 2/rm32/edx . . . 4/r32/esp . . # copy esp to edx 1471 # size 'ed' for the calls to 'get-or-stop' 1472 # . tailor-exit-descriptor(ed, 24) 1473 # . . push args 1474 68/push 0x18/imm32/nbytes-of-args-for-get-or-stop 1475 52/push-edx 1476 # . . call 1477 e8/call tailor-exit-descriptor/disp32 1478 # . . discard args 1479 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1480 # insert(table, "code", 12 bytes/row, Heap) 1481 # . . push args 1482 68/push Heap/imm32 1483 68/push 0xc/imm32/row-size 1484 68/push "code"/imm32 1485 51/push-ecx 1486 # . . call 1487 e8/call get-or-insert/disp32 1488 # . . discard args 1489 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp 1490 $test-get-or-stop:success: 1491 # eax = get-or-stop(table, "code", row-size=12, msg, _test-error-buffered-file, ed) 1492 # . . push args 1493 52/push-edx/ed 1494 68/push _test-error-buffered-file/imm32 1495 68/push "foo"/imm32/abort-prefix 1496 68/push 0xc/imm32/row-size 1497 68/push "code"/imm32 1498 51/push-ecx 1499 # . . call 1500 e8/call get-or-stop/disp32 1501 # . . discard args 1502 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x18/imm32 # add to esp 1503 $test-get-or-stop:success-assertion: 1504 # check-ints-equal(eax - table->data, 8, msg) 1505 # . check-ints-equal(eax - table, 20, msg) 1506 # . . push args 1507 68/push "F - test-get-or-stop/0"/imm32 1508 68/push 0x14/imm32 1509 29/subtract 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . . # subtract ecx from eax 1510 50/push-eax 1511 # . . call 1512 e8/call check-ints-equal/disp32 1513 # . . discard args 1514 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1515 $test-get-or-stop:failure: 1516 # eax = get-or-stop(table, "data", row-size=12, msg, _test-error-buffered-file, ed) 1517 # . . push args 1518 52/push-edx/ed 1519 68/push _test-error-buffered-file/imm32 1520 68/push "foo"/imm32/abort-prefix 1521 68/push 0xc/imm32/row-size 1522 68/push "data"/imm32 1523 51/push-ecx 1524 # . . call 1525 e8/call get-or-stop/disp32 1526 # registers except esp may be clobbered at this point 1527 # restore register args, discard others 1528 59/pop-to-ecx 1529 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp 1530 5a/pop-to-edx 1531 $test-get-or-stop:failure-assertion: 1532 # check that get-or-stop tried to call stop(1) 1533 # . check-ints-equal(ed->value, 2, msg) 1534 # . . push args 1535 68/push "F - test-get-or-stop/1"/imm32 1536 68/push 2/imm32 1537 # . . push ed->value 1538 ff 6/subop/push 1/mod/*+disp8 2/rm32/edx . . . . 4/disp8 . # push *(edx+4) 1539 # . . call 1540 e8/call check-ints-equal/disp32 1541 # . . discard args 1542 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1543 $test-get-or-stop:end: 1544 # . epilogue 1545 # don't restore esp from ebp; manually reclaim locals 1546 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x2c/imm32 # add to esp 1547 5d/pop-to-ebp 1548 c3/return 1549 1550 # if no row is found, stop(ed) 1551 get-slice-or-stop: # table: (addr stream {(handle array byte), _}), key: (addr slice), row-size: int, 1552 # abort-message-prefix: (addr string), err: (addr buffered-file), ed: (addr exit-descriptor) 1553 # -> result/eax: (addr _) 1554 # pseudocode: 1555 # curr = table->data 1556 # max = &table->data[table->write] 1557 # while curr < max 1558 # var c: (addr array byte) = lookup(*curr) 1559 # if slice-equal?(key, c) 1560 # return curr+8 1561 # curr += row-size 1562 # write-buffered(err, msg) 1563 # stop(ed) 1564 # 1565 # . prologue 1566 55/push-ebp 1567 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 1568 # . save registers 1569 51/push-ecx 1570 52/push-edx 1571 56/push-esi 1572 # esi = table 1573 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 . # copy *(ebp+8) to esi 1574 # var curr/ecx: (addr handle array byte) = table->data 1575 8d/copy-address 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 0xc/disp8 . # copy esi+12 to ecx 1576 # var max/edx: (addr byte) = &table->data[table->write] 1577 8b/copy 0/mod/indirect 6/rm32/esi . . . 2/r32/edx . . # copy *esi to edx 1578 8d/copy-address 0/mod/indirect 4/rm32/sib 1/base/ecx 2/index/edx . 2/r32/edx . . # copy ecx+edx to edx 1579 $get-slice-or-stop:search-loop: 1580 # if (curr >= max) stop(ed) 1581 39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx 1582 73/jump-if-addr>= $get-slice-or-stop:stop/disp8 1583 # var c/eax: (addr array byte) = lookup(*curr) 1584 # . . push args 1585 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 4/disp8 . # push *(ecx+4) 1586 ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . . # push *ecx 1587 # . . call 1588 e8/call lookup/disp32 1589 # . . discard args 1590 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1591 # if (slice-equal?(key, c)) return curr+4 1592 # . eax = slice-equal?(key, c) 1593 # . . push args 1594 50/push-eax 1595 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) 1596 # . . call 1597 e8/call slice-equal?/disp32 1598 # . . discard args 1599 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1600 # . if (eax != false) return eax = curr+8 1601 3d/compare-eax-and 0/imm32/false 1602 74/jump-if-= $get-slice-or-stop:mismatch/disp8 1603 8d/copy-address 1/mod/*+disp8 1/rm32/ecx . . . 0/r32/eax 8/disp8 . # copy ecx+8 to eax 1604 eb/jump $get-slice-or-stop:end/disp8 1605 $get-slice-or-stop:mismatch: 1606 # curr += row-size 1607 03/add 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 0x10/disp8 . # add *(ebp+16) to ecx 1608 # loop 1609 eb/jump $get-slice-or-stop:search-loop/disp8 1610 $get-slice-or-stop:end: 1611 # . restore registers 1612 5e/pop-to-esi 1613 5a/pop-to-edx 1614 59/pop-to-ecx 1615 # . epilogue 1616 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 1617 5d/pop-to-ebp 1618 c3/return 1619 1620 $get-slice-or-stop:stop: 1621 # . write-buffered(err, abort-message-prefix) 1622 # . . push args 1623 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x14/disp8 . # push *(ebp+20) 1624 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x18/disp8 . # push *(ebp+24) 1625 # . . call 1626 e8/call write-buffered/disp32 1627 # . . discard args 1628 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1629 # . write-buffered(err, error) 1630 # . . push args 1631 68/push ": get-slice-or-stop: key not found: "/imm32 1632 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x18/disp8 . # push *(ebp+24) 1633 # . . call 1634 e8/call write-buffered/disp32 1635 # . . discard args 1636 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1637 # . write-slice-buffered(err, key) 1638 # . . push args 1639 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) 1640 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x18/disp8 . # push *(ebp+24) 1641 # . . call 1642 e8/call write-slice-buffered/disp32 1643 # . . discard args 1644 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1645 # . write-buffered(err, "\n") 1646 # . . push args 1647 68/push Newline/imm32 1648 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x18/disp8 . # push *(ebp+24) 1649 # . . call 1650 e8/call write-buffered/disp32 1651 # . . discard args 1652 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1653 # . stop(ed, 1) 1654 # . . push args 1655 68/push 1/imm32 1656 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x1c/disp8 . # push *(ebp+28) 1657 # . . call 1658 e8/call stop/disp32 1659 # never gets here 1660 $get-slice-or-stop:terminus: 1661 # . . discard args 1662 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1663 # syscall(exit, 1) 1664 bb/copy-to-ebx 1/imm32 1665 e8/call syscall_exit/disp32 1666 1667 test-get-slice-or-stop: 1668 # This test uses exit-descriptors. Use ebp for setting up local variables. 1669 # . prologue 1670 55/push-ebp 1671 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 1672 # setup 1673 # . clear-stream(_test-error-stream) 1674 # . . push args 1675 68/push _test-error-stream/imm32 1676 # . . call 1677 e8/call clear-stream/disp32 1678 # . . discard args 1679 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1680 # . clear-stream($_test-error-buffered-file->buffer) 1681 # . . push args 1682 68/push $_test-error-buffered-file->buffer/imm32 1683 # . . call 1684 e8/call clear-stream/disp32 1685 # . . discard args 1686 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1687 # var table/ecx: (stream {string, number} 24) # 2 rows * 12 bytes/row 1688 81 5/subop/subtract 3/mod/direct 4/rm32/esp . . . . . 0x18/imm32 # subtract from esp 1689 68/push 0x18/imm32/size 1690 68/push 0/imm32/read 1691 68/push 0/imm32/write 1692 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 1693 # var ed/edx: exit-descriptor 1694 68/push 0/imm32 1695 68/push 0/imm32 1696 89/copy 3/mod/direct 2/rm32/edx . . . 4/r32/esp . . # copy esp to edx 1697 # var slice/ebx: slice = "code" 1698 # . (eax..ebx) = "code" 1699 b8/copy-to-eax "code"/imm32 1700 8b/copy 0/mod/indirect 0/rm32/eax . . . 3/r32/ebx . . # copy *eax to ebx 1701 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 3/index/ebx . 3/r32/ebx 4/disp8 . # copy eax+ebx+4 to ebx 1702 05/add-to-eax 4/imm32 1703 # . ebx = {eax, ebx} 1704 53/push-ebx 1705 50/push-eax 1706 89/copy 3/mod/direct 3/rm32/ebx . . . 4/r32/esp . . # copy esp to ebx 1707 # size 'ed' for the calls to 'get-or-stop' (define no locals past this point) 1708 # . tailor-exit-descriptor(ed, 24) 1709 # . . push args 1710 68/push 0x18/imm32/nbytes-of-args-for-get-or-stop 1711 52/push-edx 1712 # . . call 1713 e8/call tailor-exit-descriptor/disp32 1714 # . . discard args 1715 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1716 # insert(table, "code", 12 bytes/row, Heap) 1717 # . . push args 1718 68/push Heap/imm32 1719 68/push 0xc/imm32/row-size 1720 68/push "code"/imm32 1721 51/push-ecx 1722 # . . call 1723 e8/call get-or-insert/disp32 1724 # . . discard args 1725 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp 1726 $test-get-slice-or-stop:success: 1727 # eax = get-slice-or-stop(table, slice, row-size=12, msg, _test-error-buffered-file, ed) 1728 # . . push args 1729 52/push-edx/ed 1730 68/push _test-error-buffered-file/imm32 1731 68/push "foo"/imm32/abort-prefix 1732 68/push 0xc/imm32/row-size 1733 53/push-ebx/slice 1734 51/push-ecx 1735 # . . call 1736 e8/call get-slice-or-stop/disp32 1737 # registers except esp may be clobbered at this point 1738 # restore register args, discard others 1739 59/pop-to-ecx 1740 5b/pop-to-ebx 1741 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1742 5a/pop-to-edx 1743 $test-get-slice-or-stop:success-assertion: 1744 # check-ints-equal(eax - table->data, 8, msg) # first row's value slot returned 1745 # . check-ints-equal(eax - table, 20, msg) 1746 # . . push args 1747 68/push "F - test-get-slice-or-stop/0"/imm32 1748 68/push 0x14/imm32 1749 29/subtract 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . . # subtract ecx from eax 1750 50/push-eax 1751 # . . call 1752 e8/call check-ints-equal/disp32 1753 # . . discard args 1754 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1755 $test-get-slice-or-stop:failure: 1756 # slice = "segment2" 1757 # . *ebx = "segment2"->data 1758 b8/copy-to-eax "segment2"/imm32 1759 05/add-to-eax 4/imm32 1760 89/copy 0/mod/indirect 3/rm32/ebx . . . 0/r32/eax . . # copy eax to *ebx 1761 # . *(ebx+4) = "segment2"->data + len("segment2") 1762 05/add-to-eax 8/imm32/strlen 1763 89/copy 1/mod/*+disp8 3/rm32/ebx . . . 0/r32/eax 4/disp8 . # copy eax to *(ebx+4) 1764 # eax = get-slice-or-stop(table, slice, row-size=12, msg, _test-error-buffered-file, ed) 1765 # . . push args 1766 52/push-edx/ed 1767 68/push _test-error-buffered-file/imm32 1768 68/push "foo"/imm32/abort-prefix 1769 68/push 0xc/imm32/row-size 1770 53/push-ebx/slice 1771 51/push-ecx 1772 # . . call 1773 e8/call get-slice-or-stop/disp32 1774 # registers except esp may be clobbered at this point 1775 # restore register args, discard others 1776 59/pop-to-ecx 1777 5b/pop-to-ebx 1778 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1779 5a/pop-to-edx 1780 $test-get-slice-or-stop:failure-assertion: 1781 # check that get-or-stop tried to call stop(1) 1782 # . check-ints-equal(ed->value, 2, msg) 1783 # . . push args 1784 68/push "F - test-get-or-stop/1"/imm32 1785 68/push 2/imm32 1786 # . . push ed->value 1787 ff 6/subop/push 1/mod/*+disp8 2/rm32/edx . . . . 4/disp8 . # push *(edx+4) 1788 # . . call 1789 e8/call check-ints-equal/disp32 1790 # . . discard args 1791 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1792 $test-get-slice-or-stop:end: 1793 # . epilogue 1794 # don't restore esp from ebp; manually reclaim locals 1795 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x34/imm32 # add to esp 1796 5d/pop-to-ebp 1797 c3/return 1798 1799 # if no row is found, return null (0) 1800 maybe-get: # table: (addr stream {(handle array byte), T}), key: (addr array byte), row-size: int -> result/eax: (addr T) 1801 # pseudocode: 1802 # curr = table->data 1803 # max = &table->data[table->write] 1804 # while curr < max 1805 # var c: (addr array byte) = lookup(*curr) 1806 # if string-equal?(key, c) 1807 # return curr+8 1808 # curr += row-size 1809 # return 0 1810 # 1811 # . prologue 1812 55/push-ebp 1813 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 1814 # . save registers 1815 51/push-ecx 1816 52/push-edx 1817 56/push-esi 1818 # esi = table 1819 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 . # copy *(ebp+8) to esi 1820 # var curr/ecx: (addr handle array byte) = table->data 1821 8d/copy-address 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 0xc/disp8 . # copy esi+12 to ecx 1822 # var max/edx: (addr byte) = &table->data[table->write] 1823 8b/copy 0/mod/indirect 6/rm32/esi . . . 2/r32/edx . . # copy *esi to edx 1824 8d/copy-address 0/mod/indirect 4/rm32/sib 1/base/ecx 2/index/edx . 2/r32/edx . . # copy ecx+edx to edx 1825 $maybe-get:search-loop: 1826 # if (curr >= max) return null 1827 39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx 1828 73/jump-if-addr>= $maybe-get:null/disp8 1829 # var c/eax: (addr array byte) = lookup(*curr) 1830 # . . push args 1831 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 4/disp8 . # push *(ecx+4) 1832 ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . . # push *ecx 1833 # . . call 1834 e8/call lookup/disp32 1835 # . . discard args 1836 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1837 # if (string-equal?(key, c)) return curr+4 1838 # . eax = string-equal?(key, c) 1839 # . . push args 1840 50/push-eax 1841 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) 1842 # . . call 1843 e8/call string-equal?/disp32 1844 # . . discard args 1845 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1846 # . if (eax != false) return eax = curr+8 1847 3d/compare-eax-and 0/imm32/false 1848 74/jump-if-= $maybe-get:mismatch/disp8 1849 8d/copy-address 1/mod/*+disp8 1/rm32/ecx . . . 0/r32/eax 8/disp8 . # copy ecx+8 to eax 1850 eb/jump $maybe-get:end/disp8 1851 $maybe-get:mismatch: 1852 # curr += row-size 1853 03/add 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 0x10/disp8 . # add *(ebp+16) to ecx 1854 # loop 1855 eb/jump $maybe-get:search-loop/disp8 1856 $maybe-get:null: 1857 b8/copy-to-eax 0/imm32 1858 $maybe-get:end: 1859 # . restore registers 1860 5e/pop-to-esi 1861 5a/pop-to-edx 1862 59/pop-to-ecx 1863 # . epilogue 1864 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 1865 5d/pop-to-ebp 1866 c3/return 1867 1868 test-maybe-get: 1869 # . prologue 1870 55/push-ebp 1871 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 1872 # - setup: create a table with one row 1873 # var table/ecx: (stream {string, number} 24) # 2 rows * 12 bytes/row 1874 81 5/subop/subtract 3/mod/direct 4/rm32/esp . . . . . 0x18/imm32 # subtract from esp 1875 68/push 0x18/imm32/size 1876 68/push 0/imm32/read 1877 68/push 0/imm32/write 1878 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 1879 # eax = get-or-insert(table, "code", 12 bytes/row, Heap) 1880 # . . push args 1881 68/push Heap/imm32 1882 68/push 0xc/imm32/row-size 1883 68/push "code"/imm32 1884 51/push-ecx 1885 # . . call 1886 e8/call get-or-insert/disp32 1887 # . . discard args 1888 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp 1889 $test-maybe-get:success: 1890 # - check for the same key, verify that it was reused 1891 # eax = maybe-get(table, "code", 12 bytes/row) 1892 # . . push args 1893 68/push 0xc/imm32/row-size 1894 68/push "code"/imm32 1895 51/push-ecx 1896 # . . call 1897 e8/call maybe-get/disp32 1898 # . . discard args 1899 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1900 # check-ints-equal(eax - table->data, 8, msg) 1901 # . check-ints-equal(eax - table, 20, msg) 1902 # . . push args 1903 68/push "F - test-maybe-get/0"/imm32 1904 68/push 0x14/imm32 1905 29/subtract 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . . # subtract ecx from eax 1906 50/push-eax 1907 # . . call 1908 e8/call check-ints-equal/disp32 1909 # . . discard args 1910 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1911 # no new row inserted 1912 # . check-ints-equal(table->write, row-size = 12, msg) 1913 # . . push args 1914 68/push "F - test-maybe-get/1"/imm32 1915 68/push 0xc/imm32/row-size 1916 ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . . # push *ecx 1917 # . . call 1918 e8/call check-ints-equal/disp32 1919 # . . discard args 1920 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1921 # var curr-addr/eax: (addr array byte) = lookup(table->data) 1922 # . . push args 1923 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 0x10/disp8 . # push *(ecx+16) 1924 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 0xc/disp8 . # push *(ecx+12) 1925 # . . call 1926 e8/call lookup/disp32 1927 # . . discard args 1928 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1929 # check-strings-equal(curr-addr, "code", msg) 1930 # . . push args 1931 68/push "F - test-maybe-get/2"/imm32 1932 68/push "code"/imm32 1933 50/push-eax 1934 # . . call 1935 e8/call check-strings-equal/disp32 1936 # . . discard args 1937 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1938 $test-maybe-get:failure: 1939 # - search for a new key 1940 # eax = maybe-get(table, "data", 12 bytes/row) 1941 # . . push args 1942 68/push 0xc/imm32/row-size 1943 68/push "data"/imm32 1944 51/push-ecx 1945 # . . call 1946 e8/call maybe-get/disp32 1947 # . . discard args 1948 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1949 # check-ints-equal(eax, 0, msg) 1950 # . . push args 1951 68/push "F - test-maybe-get/3"/imm32 1952 68/push 0/imm32 1953 50/push-eax 1954 # . . call 1955 e8/call check-ints-equal/disp32 1956 # . . discard args 1957 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1958 $test-maybe-get:end: 1959 # . epilogue 1960 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 1961 5d/pop-to-ebp 1962 c3/return 1963 1964 # if no row is found, return null (0) 1965 maybe-get-slice: # table: (addr stream {(handle array byte), T}), key: (addr slice), row-size: int -> result/eax: (addr T) 1966 # pseudocode: 1967 # curr = table->data 1968 # max = &table->data[table->write] 1969 # while curr < max 1970 # var c: (addr array byte) = lookup(*curr) 1971 # if slice-equal?(key, c) 1972 # return curr+8 1973 # curr += row-size 1974 # return 0 1975 # 1976 # . prologue 1977 55/push-ebp 1978 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 1979 # . save registers 1980 51/push-ecx 1981 52/push-edx 1982 56/push-esi 1983 # esi = table 1984 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 . # copy *(ebp+8) to esi 1985 # var curr/ecx: (addr handle array byte) = table->data 1986 8d/copy-address 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 0xc/disp8 . # copy esi+12 to ecx 1987 # var max/edx: (addr byte) = &table->data[table->write] 1988 8b/copy 0/mod/indirect 6/rm32/esi . . . 2/r32/edx . . # copy *esi to edx 1989 8d/copy-address 0/mod/indirect 4/rm32/sib 1/base/ecx 2/index/edx . 2/r32/edx . . # copy ecx+edx to edx 1990 $maybe-get-slice:search-loop: 1991 # if (curr >= max) return null 1992 39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx 1993 73/jump-if-addr>= $maybe-get-slice:null/disp8 1994 # var c/eax: (addr array byte) = lookup(*curr) 1995 # . . push args 1996 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 4/disp8 . # push *(ecx+4) 1997 ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . . # push *ecx 1998 # . . call 1999 e8/call lookup/disp32 2000 # . . discard args 2001 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 2002 # if (slice-equal?(key, c)) return curr+4 2003 # . eax = slice-equal?(key, c) 2004 # . . push args 2005 50/push-eax 2006 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) 2007 # . . call 2008 e8/call slice-equal?/disp32 2009 # . . discard args 2010 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 2011 # . if (eax != false) return eax = curr+8 2012 3d/compare-eax-and 0/imm32/false 2013 74/jump-if-= $maybe-get-slice:mismatch/disp8 2014 8d/copy-address 1/mod/*+disp8 1/rm32/ecx . . . 0/r32/eax 8/disp8 . # copy ecx+8 to eax 2015 eb/jump $maybe-get-slice:end/disp8 2016 $maybe-get-slice:mismatch: 2017 # curr += row-size 2018 03/add 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 0x10/disp8 . # add *(ebp+16) to ecx 2019 # loop 2020 eb/jump $maybe-get-slice:search-loop/disp8 2021 $maybe-get-slice:null: 2022 b8/copy-to-eax 0/imm32 2023 $maybe-get-slice:end: 2024 # . restore registers 2025 5e/pop-to-esi 2026 5a/pop-to-edx 2027 59/pop-to-ecx 2028 # . epilogue 2029 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 2030 5d/pop-to-ebp 2031 c3/return 2032 2033 test-maybe-get-slice: 2034 # . prologue 2035 55/push-ebp 2036 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 2037 # - setup: create a table with one row 2038 # var table/ecx: (stream {string, number} 24) # 2 rows * 12 bytes/row 2039 81 5/subop/subtract 3/mod/direct 4/rm32/esp . . . . . 0x18/imm32 # subtract from esp 2040 68/push 0x18/imm32/size 2041 68/push 0/imm32/read 2042 68/push 0/imm32/write 2043 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 2044 # insert(table, "code", 12 bytes/row, Heap) 2045 # . . push args 2046 68/push Heap/imm32 2047 68/push 0xc/imm32/row-size 2048 68/push "code"/imm32 2049 51/push-ecx 2050 # . . call 2051 e8/call get-or-insert/disp32 2052 # . . discard args 2053 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp 2054 $test-maybe-get-slice:success: 2055 # - check for the same key, verify that it was reused 2056 # (eax..edx) = "code" 2057 b8/copy-to-eax "code"/imm32 2058 8b/copy 0/mod/indirect 0/rm32/eax . . . 2/r32/edx . . # copy *eax to edx 2059 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 2/index/edx . 2/r32/edx 4/disp8 . # copy eax+edx+4 to edx 2060 05/add-to-eax 4/imm32 2061 # var slice/edx: slice = {eax, edx} 2062 52/push-edx 2063 50/push-eax 2064 89/copy 3/mod/direct 2/rm32/edx . . . 4/r32/esp . . # copy esp to edx 2065 # eax = maybe-get-slice(table, "code" slice, 12 bytes/row) 2066 # . . push args 2067 68/push 0xc/imm32/row-size 2068 52/push-edx 2069 51/push-ecx 2070 # . . call 2071 e8/call maybe-get-slice/disp32 2072 # . . discard args 2073 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 2074 # check-ints-equal(eax - table->data, 8, msg) 2075 # . check-ints-equal(eax - table, 20, msg) 2076 # . . push args 2077 68/push "F - test-maybe-get-slice/0"/imm32 2078 68/push 0x14/imm32 2079 29/subtract 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . . # subtract ecx from eax 2080 50/push-eax 2081 # . . call 2082 e8/call check-ints-equal/disp32 2083 # . . discard args 2084 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 2085 # no new row inserted 2086 # . check-ints-equal(table->write, row-size = 12, msg) 2087 # . . push args 2088 68/push "F - test-maybe-get-slice/1"/imm32 2089 68/push 0xc/imm32/row-size 2090 ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . . # push *ecx 2091 # . . call 2092 e8/call check-ints-equal/disp32 2093 # . . discard args 2094 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 2095 # var curr-addr/eax: (addr array byte) = lookup(table->data) 2096 # . . push args 2097 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 0x10/disp8 . # push *(ecx+16) 2098 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 0xc/disp8 . # push *(ecx+12) 2099 # . . call 2100 e8/call lookup/disp32 2101 # . . discard args 2102 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 2103 # check-strings-equal(curr-addr, "code", msg) 2104 # . . push args 2105 68/push "F - test-maybe-get-slice/2"/imm32 2106 68/push "code"/imm32 2107 50/push-eax 2108 # . . call 2109 e8/call check-strings-equal/disp32 2110 # . . discard args 2111 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 2112 $test-maybe-get-slice:failure: 2113 # - search for a new key 2114 # (eax..edx) = "data" 2115 b8/copy-to-eax "data"/imm32 2116 8b/copy 0/mod/indirect 0/rm32/eax . . . 2/r32/edx . . # copy *eax to edx 2117 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 2/index/edx . 2/r32/edx 4/disp8 . # copy eax+edx+4 to edx 2118 05/add-to-eax 4/imm32 2119 # var slice/edx: slice = {eax, edx} 2120 52/push-edx 2121 50/push-eax 2122 89/copy 3/mod/direct 2/rm32/edx . . . 4/r32/esp . . # copy esp to edx 2123 # eax = maybe-get-slice(table, "data" slice, 12 bytes/row) 2124 # . . push args 2125 68/push 0xc/imm32/row-size 2126 52/push-edx 2127 51/push-ecx 2128 # . . call 2129 e8/call maybe-get-slice/disp32 2130 # . . discard args 2131 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 2132 # check-ints-equal(eax, 0, msg) 2133 # . . push args 2134 68/push "F - test-maybe-get-slice/3"/imm32 2135 68/push 0/imm32 2136 50/push-eax 2137 # . . call 2138 e8/call check-ints-equal/disp32 2139 # . . discard args 2140 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 2141 $test-maybe-get-slice:end: 2142 # . epilogue 2143 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 2144 5d/pop-to-ebp 2145 c3/return 2146 2147 # . . vim:nowrap:textwidth=0