https://github.com/akkartik/mu/blob/master/081table.subx
   1 # A table is a stream of (key, value) rows.
   2 #
   3 # Each row consists of a 4-byte key -- a 'string_key' which is (addr array
   4 # byte) -- and a variable-size value.
   5 #
   6 # Accessing the table performs a linear scan for a key string, and always
   7 # requires passing in the row size.
   8 #
   9 # Table primitives have the form <variant>(stream, <arg>, row-size, ...) -> address/eax
  10 #
  11 # The following table shows available options for <variant>:
  12 #   if not found:           | arg=string              arg=slice
  13 #   ------------------------+---------------------------------------------------
  14 #   abort                   | get                     get-slice
  15 #   insert key              | get-or-insert           leaky-get-or-insert-slice
  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 # type string_key = (addr array byte)
  27 get:  # table: (addr stream {string_key, T}), key: string_key, row-size: int, abort-message-prefix: (addr array byte) -> eax: (addr T)
  28     # pseudocode:
  29     #   curr = table->data
  30     #   max = &table->data[table->write]
  31     #   while curr < max
  32     #     if string-equal?(key, *curr)
  33     #       return curr+4
  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 string_key) = 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     # if (string-equal?(key, *curr)) return curr+4
  56     # . eax = string-equal?(key, *curr)
  57     # . . pu
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html><head><title>Python: module ranger.fsobject.fsobject</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head><body bgcolor="#f0f0f8">

<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="heading">
<tr bgcolor="#7799ee">
<td valign=bottom>&nbsp;<br>
<font color="#ffffff" face="helvetica, arial">&nbsp;<br><big><big><strong><a href="ranger.html"><font color="#ffffff">ranger</font></a>.<a href="ranger.fsobject.html"><font color="#ffffff">fsobject</font></a>.fsobject</strong></big></big></font></td
><td align=right valign=bottom
><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/home/hut/work/ranger/ranger/fsobject/fsobject.py">/home/hut/work/ranger/ranger/fsobject/fsobject.py</a></font></td></tr></table>
    <p></p>
<p>
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
<tr bgcolor="#ee77aa">
<td colspan=3 valign=bottom>&nbsp;<br>
<font color="#ffffff" face="helvetica, arial"><big><strong>Classes</strong></big></font></td></tr>
    
<tr><td bgcolor="#ee77aa"><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</tt></td><td>&nbsp;</td>
<td width="100%"><dl>
<dt><font face="helvetica, arial"><a href="ranger.shared.html#FileManagerAware">ranger.shared.FileManagerAware</a>(<a href="ranger.shared.html#Awareness">ranger.shared.Awareness</a>)
</font></dt><dd>
<dl>
<dt><font face="helvetica, arial"><a href="ranger.fsobject.fsobject.html#FileSystemObject">FileSystemObject</a>(<a href="ranger.shared.mimetype.html#MimeTypeAware">ranger.shared.mimetype.MimeTypeAware</a>, <a href="ranger.shared.html#FileManagerAware">ranger.shared.FileManagerAware</a>)
</font></dt></dl>
</dd>
<dt><font face="helvetica, arial"><a href="ranger.shared.mimetype.html#MimeTypeAware">ranger.shared.mimetype.MimeTypeAware</a>(<a href="builtins.html#object">builtins.object</a>)
</font></dt><dd>
<dl>
<dt><font face="helvetica, arial"><a href="ranger.fsobject.fsobject.html#FileSystemObject">FileSystemObject</a>(<a href="ranger.shared.mimetype.html#MimeTypeAware">ranger.shared.mimetype.MimeTypeAware</a>, <a href="ranger.shared.html#FileManagerAware">ranger.shared.FileManagerAware</a>)
</font></dt></dl>
</dd>
</dl>
 <p>
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
<tr bgcolor="#ffc8d8">
<td colspan=3 valign=bottom>&nbsp;<br>
<font color="#000000" face="helvetica, arial"><a name="FileSystemObject">class <strong>FileSystemObject</strong></a>(<a href="ranger.shared.mimetype.html#MimeTypeAware">ranger.shared.mimetype.MimeTypeAware</a>, <a href="ranger.shared.html#FileManagerAware">ranger.shared.FileManagerAware</a>)</font></td></tr>
    
<tr><td bgcolor="#ffc8d8"><tt>&nbsp;&nbsp;&nbsp;</tt></td><td>&nbsp;</td>
<td width="100%"><dl><dt>Method resolution order:</dt>
<dd><a href="ranger.fsobject.fsobject.html#FileSystemObject">FileSystemObject</a></dd>
<dd><a href="ranger.shared.mimetype.html#MimeTypeAware">ranger.shared.mimetype.MimeTypeAware</a></dd>
<dd><a href="ranger.shared.html#FileManagerAware">ranger.shared.FileManagerAware</a></dd>
<dd><a href="ranger.shared.html#Awareness">ranger.shared.Awareness</a></dd>
<dd><a href="builtins.html#object">builtins.object</a></dd>
</dl>
<hr>
Methods defined here:<br>
<dl><dt><a name="FileSystemObject-__init__"><strong>__init__</strong></a>(self, path)</dt></dl>

<dl><dt><a name="FileSystemObject-__str__"><strong>__str__</strong></a>(self)</dt><dd><tt>returns&nbsp;a&nbsp;string&nbsp;containing&nbsp;the&nbsp;absolute&nbsp;path</tt></dd></dl>

<dl><dt><a name="FileSystemObject-get_description"><strong>get_description</strong></a>(self)</dt></dl>

<dl><dt><a name="FileSystemObject-get_permission_string"><strong>get_permission_string</strong></a>(self)</dt></dl>

<dl><dt><a name="FileSystemObject-go"><strong>go</strong></a>(self)</dt><dd><tt>enter&nbsp;the&nbsp;directory&nbsp;if&nbsp;the&nbsp;filemanager&nbsp;is&nbsp;running</tt></dd></dl>

<dl><dt><a name="FileSystemObject-is_older_than"><strong>is_older_than</strong></a>(self, seconds)</dt><dd><tt>returns&nbsp;whether&nbsp;this&nbsp;object&nbsp;wasn't&nbsp;<a href="#FileSystemObject-use">use</a>()d&nbsp;in&nbsp;the&nbsp;last&nbsp;n&nbsp;seconds</tt></dd></dl>

<dl><dt><a name="FileSystemObject-load"><strong>load</strong></a>(self)</dt><dd><tt>reads&nbsp;useful&nbsp;information&nbsp;about&nbsp;the&nbsp;filesystem-object&nbsp;from&nbsp;the<br>
filesystem&nbsp;and&nbsp;caches&nbsp;it&nbsp;for&nbsp;later&nbsp;use</tt></dd></dl>

<dl><dt><a name="FileSystemObject-load_if_outdated"><strong>load_if_outdated</strong></a>(self)</dt><dd><tt>Calls&nbsp;<a href="#FileSystemObject-load">load</a>()&nbsp;if&nbsp;the&nbsp;currently&nbsp;cached&nbsp;information&nbsp;is&nbsp;outdated<br>
or&nbsp;nonexistant.</tt></dd></dl>

<dl><dt><a name="FileSystemObject-load_once"><strong>load_once</strong></a>(self)</dt><dd><tt>calls&nbsp;<a href="#FileSystemObject-load">load</a>()&nbsp;if&nbsp;it&nbsp;has&nbsp;not&nbsp;been&nbsp;called&nbsp;at&nbsp;least&nbsp;once&nbsp;yet</tt></dd></dl>

<dl><dt><a name="FileSystemObject-mark"><strong>mark</strong></a>(self, boolean)</dt></dl>

<dl><dt><a name="FileSystemObject-set_mimetype"><strong>set_mimetype</strong></a>(self)</dt><dd><tt>assign&nbsp;attributes&nbsp;such&nbsp;as&nbsp;self.<strong>video</strong>&nbsp;according&nbsp;to&nbsp;the&nbsp;mimetype</tt></dd></dl>

<dl><dt><a name="FileSystemObject-use"><strong>use</strong></a>(self)</dt><dd><tt>mark&nbsp;the&nbsp;filesystem-object&nbsp;as&nbsp;used&nbsp;at&nbsp;the&nbsp;current&nbsp;time</tt></dd></dl>

<hr>
Data and other attributes defined here:<br>
<dl><dt><strong>accessible</strong> = False</dl>

<dl><dt><strong>audio</strong> = False</dl>

<dl><dt><strong>basename</strong> = None</dl>

<dl><dt><strong>basename_lower</strong> = None</dl>

<dl><dt><strong>container</strong> = False</dl>

<dl><dt><strong>content_loaded</strong> = False</dl>

<dl><dt><strong>dirname</strong> = None</dl>

<dl><dt><strong>document</strong> = False</dl>

<dl><dt><strong>exists</strong> = False</dl>

<dl><dt><strong>extension</strong> = None</dl>

<dl><dt><strong>force_load</strong> = False</dl>

<dl><dt><strong>image</strong> = False</dl>

<dl><dt><strong>infostring</strong> = None</dl>

<dl><dt><strong>islink</strong> = False</dl>

<dl><dt><strong>last_used</strong> = None</dl>

<dl><dt><strong>loaded</strong> = False</dl>

<dl><dt><strong>marked</strong> = False</dl>

<dl><dt><strong>media</strong> = False</dl>

<dl><dt><strong>mimetype_tuple</strong> = ()</dl>

<dl><dt><strong>path</strong> = None</dl>

<dl><dt><strong>permissions</strong> = None</dl>

<dl><dt><strong>readlink</strong> = None</dl>

<dl><dt><strong>runnable</strong> = False</dl>

<dl><dt><strong>size</strong> = 0</dl>

<dl><dt><strong>stat</strong> = None</dl>

<dl><dt><strong>stopped</strong> = False</dl>

<dl><dt><strong>tagged</strong> = False</dl>

<dl><dt><strong>type</strong> = 'unknown'</dl>

<dl><dt><strong>video</strong> = False</dl>

<hr>
Data descriptors inherited from <a href="ranger.shared.mimetype.html#MimeTypeAware">ranger.shared.mimetype.MimeTypeAware</a>:<br>
<dl><dt><strong>__dict__</strong></dt>
<dd><tt>dictionary&nbsp;for&nbsp;instance&nbsp;variables&nbsp;(if&nbsp;defined)</tt></dd>
</dl>
<dl><dt><strong>__weakref__</strong></dt>
<dd><tt>list&nbsp;of&nbsp;weak&nbsp;references&nbsp;to&nbsp;the&nbsp;object&nbsp;(if&nbsp;defined)</tt></dd>
</dl>
<hr>
Data and other attributes inherited from <a href="ranger.shared.mimetype.html#MimeTypeAware">ranger.shared.mimetype.MimeTypeAware</a>:<br>
<dl><dt><strong>mimetypes</strong> = {}</dl>

<hr>
Data and other attributes inherited from <a href="ranger.shared.html#FileManagerAware">ranger.shared.FileManagerAware</a>:<br>
<dl><dt><strong>fm</strong> = None</dl>

</td></tr></table></td></tr></table><p>
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
<tr bgcolor="#55aa55">
<td colspan=3 valign=bottom>&nbsp;<br>
<font color="#ffffff" face="helvetica, arial"><big><strong>Data</strong></big></font></td></tr>
    
<tr><td bgcolor="#55aa55"><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</tt></td><td>&nbsp;</td>
<td width="100%"><strong>BAD_INFO</strong> = None<br>
<strong>CONTAINER_EXTENSIONS</strong> = ['rar', 'zip', 'tar', 'gz', 'bz', 'bz2', 'tgz', '7z', 'iso', 'cab']<br>
<strong>DOCUMENT_BASENAMES</strong> = ['README', 'TODO', 'LICENSE']<br>
<strong>DOCUMENT_EXTENSIONS</strong> = ['pdf', 'doc', 'ppt', 'odt']<br>
<strong>T_DIRECTORY</strong> = 'directory'<br>
<strong>T_FILE</strong> = 'file'<br>
<strong>T_NONEXISTANT</strong> = 'nonexistant'<br>
<strong>T_UNKNOWN</strong> = 'unknown'</td></tr></table>
</body></html>
ss="LineNr"> 465 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x10/disp8 . # push *(ebp+16) 466 52/push-edx 467 # . . call 468 e8/call zero-out/disp32 469 # . . discard args 470 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 471 # *max = key 472 # . eax = key 473 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 0xc/disp8 . # copy *(ebp+12) to eax 474 # . *max = eax 475 89/copy 0/mod/indirect 2/rm32/edx . . . 0/r32/eax . . # copy eax to *edx 476 # table->write += row-size 477 # . eax = row-size 478 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 0x10/disp8 . # copy *(ebp+16) to eax 479 # . table->write += eax 480 01/add 0/mod/indirect 6/rm32/esi . . . 0/r32/eax . . # add eax to *esi 481 # return max+4 482 # . eax = max 483 89/copy 3/mod/direct 0/rm32/eax . . . 2/r32/edx . . # copy edx to eax 484 # . eax += 4 485 05/add-to-eax 4/imm32 486 $get-or-insert:end: 487 # . restore registers 488 5e/pop-to-esi 489 5a/pop-to-edx 490 59/pop-to-ecx 491 # . epilogue 492 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 493 5d/pop-to-ebp 494 c3/return 495 496 $get-or-insert:abort: 497 # . _write(2/stderr, error) 498 # . . push args 499 68/push "get-or-insert: table is full\n"/imm32 500 68/push 2/imm32/stderr 501 # . . call 502 e8/call _write/disp32 503 # . . discard args 504 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 505 # . syscall(exit, 1) 506 bb/copy-to-ebx 1/imm32 507 b8/copy-to-eax 1/imm32/exit 508 cd/syscall 0x80/imm8 509 # never gets here 510 511 test-get-or-insert: 512 # . prologue 513 55/push-ebp 514 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 515 # var table/ecx: (stream {string, number} 16) # 2 rows * 8 bytes/row 516 81 5/subop/subtract 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # subtract from esp 517 68/push 0x10/imm32/length 518 68/push 0/imm32/read 519 68/push 0/imm32/write 520 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 521 $test-get-or-insert:first-call: 522 # - start with an empty table, insert one key, verify that it was inserted 523 # eax = get-or-insert(table, "code", 8 bytes per row) 524 # . . push args 525 68/push 8/imm32/row-size 526 68/push "code"/imm32 527 51/push-ecx 528 # . . call 529 e8/call get-or-insert/disp32 530 # . . discard args 531 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 532 # check-ints-equal(eax - table->data, 4, msg) # first row's value slot returned 533 # . check-ints-equal(eax - table, 16, msg) 534 # . . push args 535 68/push "F - test-get-or-insert/0"/imm32 536 68/push 0x10/imm32 537 29/subtract 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . . # subtract ecx from eax 538 50/push-eax 539 # . . call 540 e8/call check-ints-equal/disp32 541 # . . discard args 542 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 543 $test-get-or-insert:check2: 544 # check-ints-equal(table->write, row-size = 8, msg) 545 # . . push args 546 68/push "F - test-get-or-insert/1"/imm32 547 68/push 8/imm32/row-size 548 ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . . # push *ecx 549 # . . call 550 e8/call check-ints-equal/disp32 551 # . . discard args 552 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 553 # check-strings-equal(*table->data, "code", msg) 554 # . . push args 555 68/push "F - test-get-or-insert/2"/imm32 556 68/push "code"/imm32 557 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 0xc/disp8 . # push *(ecx+12) 558 # . . call 559 e8/call check-strings-equal/disp32 560 # . . discard args 561 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 562 $test-get-or-insert:second-call: 563 # - insert the same key again, verify that it was reused 564 # eax = get-or-insert(table, "code", 8 bytes per row) 565 # . . push args 566 68/push 8/imm32/row-size 567 68/push "code"/imm32 568 51/push-ecx 569 # . . call 570 e8/call get-or-insert/disp32 571 # . . discard args 572 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 573 # check-ints-equal(eax - table->data, 4, msg) 574 # . check-ints-equal(eax - table, 16, msg) 575 # . . push args 576 68/push "F - test-get-or-insert/3"/imm32 577 68/push 0x10/imm32 578 29/subtract 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . . # subtract ecx from eax 579 50/push-eax 580 # . . call 581 e8/call check-ints-equal/disp32 582 # . . discard args 583 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 584 # no new row inserted 585 # . check-ints-equal(table->write, row-size = 8, msg) 586 # . . push args 587 68/push "F - test-get-or-insert/4"/imm32 588 68/push 8/imm32/row-size 589 ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . . # push *ecx 590 # . . call 591 e8/call check-ints-equal/disp32 592 # . . discard args 593 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 594 # check-strings-equal(*table->data, "code", msg) 595 # . . push args 596 68/push "F - test-get-or-insert/5"/imm32 597 68/push "code"/imm32 598 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 0xc/disp8 . # push *(ecx+12) 599 # . . call 600 e8/call check-strings-equal/disp32 601 # . . discard args 602 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 603 $test-get-or-insert:third-call: 604 # - insert a new key, verify that it was inserted 605 # eax = get-or-insert(table, "data", 8 bytes per row) 606 # . . push args 607 68/push 8/imm32/row-size 608 68/push "data"/imm32 609 51/push-ecx 610 # . . call 611 e8/call get-or-insert/disp32 612 # . . discard args 613 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 614 # table gets a new row 615 # check-ints-equal(eax - table->data, 12, msg) # second row's value slot returned 616 # . check-ints-equal(eax - table, 24, msg) 617 # . . push args 618 68/push "F - test-get-or-insert/6"/imm32 619 68/push 0x18/imm32 620 29/subtract 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . . # subtract ecx from eax 621 50/push-eax 622 # . . call 623 e8/call check-ints-equal/disp32 624 # . . discard args 625 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 626 # check-ints-equal(table->write, 2 rows = 16, msg) 627 # . . push args 628 68/push "F - test-get-or-insert/7"/imm32 629 68/push 0x10/imm32/two-rows 630 ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . . # push *ecx 631 # . . call 632 e8/call check-ints-equal/disp32 633 # . . discard args 634 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 635 # check-strings-equal(*table->data+8, "data", msg) 636 # check-strings-equal(*(table+20), "data", msg) 637 # . . push args 638 68/push "F - test-get-or-insert/8"/imm32 639 68/push "data"/imm32 640 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 0x14/disp8 . # push *(ecx+20) 641 # . . call 642 e8/call check-strings-equal/disp32 643 # . . discard args 644 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 645 $test-get-or-insert:end: 646 # . epilogue 647 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 648 5d/pop-to-ebp 649 c3/return 650 651 # if no row is found, save 'key' in the next available row 652 # if there are no rows free, abort 653 # WARNING: leaks memory 654 # TODO: pass in an allocation descriptor 655 leaky-get-or-insert-slice: # table: (addr stream {string_key, T}), key: (addr slice), row-size: int -> eax: (addr T) 656 # pseudocode: 657 # curr = table->data 658 # max = &table->data[table->write] 659 # while curr < max 660 # if slice-equal?(key, *curr) 661 # return curr+4 662 # curr += row-size 663 # if table->write >= table->length 664 # abort 665 # zero-out(max, row-size) 666 # *max = slice-to-string(Heap, key) 667 # table->write += row-size 668 # return max+4 669 # 670 # . prologue 671 55/push-ebp 672 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 673 # . save registers 674 51/push-ecx 675 52/push-edx 676 56/push-esi 677 # esi = table 678 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 . # copy *(ebp+8) to esi 679 # var curr/ecx: (addr string_key) = table->data 680 8d/copy-address 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 0xc/disp8 . # copy esi+12 to ecx 681 # var max/edx: (addr string_key) = &table->data[table->write] 682 8b/copy 0/mod/indirect 6/rm32/esi . . . 2/r32/edx . . # copy *esi to edx 683 8d/copy-address 0/mod/indirect 4/rm32/sib 1/base/ecx 2/index/edx . 2/r32/edx . . # copy ecx+edx to edx 684 $leaky-get-or-insert-slice:search-loop: 685 # if (curr >= max) break 686 39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx 687 73/jump-if-addr>= $leaky-get-or-insert-slice:not-found/disp8 688 # if (slice-equal?(key, *curr)) return curr+4 689 # . eax = slice-equal?(key, *curr) 690 # . . push args 691 ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . . # push *ecx 692 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) 693 # . . call 694 e8/call slice-equal?/disp32 695 # . . discard args 696 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 697 # . if (eax != false) return eax = curr+4 698 3d/compare-eax-and 0/imm32/false 699 74/jump-if-= $leaky-get-or-insert-slice:mismatch/disp8 700 8d/copy-address 1/mod/*+disp8 1/rm32/ecx . . . 0/r32/eax 4/disp8 . # copy ecx+4 to eax 701 eb/jump $leaky-get-or-insert-slice:end/disp8 702 $leaky-get-or-insert-slice:mismatch: 703 # curr += row-size 704 03/add 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 0x10/disp8 . # add *(ebp+16) to ecx 705 # loop 706 eb/jump $leaky-get-or-insert-slice:search-loop/disp8 707 $leaky-get-or-insert-slice:not-found: 708 # result/eax = 0 709 31/xor 3/mod/direct 0/rm32/eax . . . 0/r32/eax . . # clear eax 710 # if (table->write >= table->length) abort 711 8b/copy 0/mod/indirect 6/rm32/esi . . . 1/r32/ecx . . # copy *esi to ecx 712 3b/compare 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 8/disp8 . # compare ecx with *(esi+8) 713 7d/jump-if->= $leaky-get-or-insert-slice:abort/disp8 714 # zero-out(max, row-size) 715 # . . push args 716 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x10/disp8 . # push *(ebp+16) 717 52/push-edx 718 # . . call 719 e8/call zero-out/disp32 720 # . . discard args 721 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 722 # *max = slice-to-string(Heap, key) 723 # . eax = slice-to-string(Heap, key) 724 # . . push args 725 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) 726 68/push Heap/imm32 727 # . . call 728 e8/call slice-to-string/disp32 729 # . . discard args 730 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 731 # . *max = eax 732 89/copy 0/mod/indirect 2/rm32/edx . . . 0/r32/eax . . # copy eax to *edx 733 # table->write += row-size 734 # . eax = row-size 735 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 0x10/disp8 . # copy *(ebp+16) to eax 736 # . table->write += eax 737 01/add 0/mod/indirect 6/rm32/esi . . . 0/r32/eax . . # add eax to *esi 738 # return max+4 739 # . eax = max 740 89/copy 3/mod/direct 0/rm32/eax . . . 2/r32/edx . . # copy edx to eax 741 # . eax += 4 742 05/add-to-eax 4/imm32 743 $leaky-get-or-insert-slice:end: 744 # . restore registers 745 5e/pop-to-esi 746 5a/pop-to-edx 747 59/pop-to-ecx 748 # . epilogue 749 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 750 5d/pop-to-ebp 751 c3/return 752 753 $leaky-get-or-insert-slice:abort: 754 # . _write(2/stderr, error) 755 # . . push args 756 68/push "leaky-get-or-insert-slice: table is full\n"/imm32 757 68/push 2/imm32/stderr 758 # . . call 759 e8/call _write/disp32 760 # . . discard args 761 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 762 # . syscall(exit, 1) 763 bb/copy-to-ebx 1/imm32 764 b8/copy-to-eax 1/imm32/exit 765 cd/syscall 0x80/imm8 766 # never gets here 767 768 test-leaky-get-or-insert-slice: 769 # . prologue 770 55/push-ebp 771 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 772 # var table/ecx: (stream {string, number} 16) # 2 rows * 8 bytes/row 773 81 5/subop/subtract 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # subtract from esp 774 68/push 0x10/imm32/length 775 68/push 0/imm32/read 776 68/push 0/imm32/write 777 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 778 # (eax..edx) = "code" 779 b8/copy-to-eax "code"/imm32 780 8b/copy 0/mod/indirect 0/rm32/eax . . . 2/r32/edx . . # copy *eax to edx 781 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 782 05/add-to-eax 4/imm32 783 # var slice/edx: slice = {eax, edx} 784 52/push-edx 785 50/push-eax 786 89/copy 3/mod/direct 2/rm32/edx . . . 4/r32/esp . . # copy esp to edx 787 $test-leaky-get-or-insert-slice:first-call: 788 # - start with an empty table, insert one key, verify that it was inserted 789 # eax = leaky-get-or-insert-slice(table, "code" slice, 8 bytes per row) 790 # . . push args 791 68/push 8/imm32/row-size 792 52/push-edx 793 51/push-ecx 794 # . . call 795 e8/call leaky-get-or-insert-slice/disp32 796 # . . discard args 797 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 798 # check-ints-equal(eax - table->data, 4, msg) # first row's value slot returned 799 # . check-ints-equal(eax - table, 16, msg) 800 # . . push args 801 68/push "F - test-leaky-get-or-insert-slice/0"/imm32 802 68/push 0x10/imm32 803 29/subtract 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . . # subtract ecx from eax 804 50/push-eax 805 # . . call 806 e8/call check-ints-equal/disp32 807 # . . discard args 808 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 809 $test-leaky-get-or-insert-slice:check2: 810 # check-ints-equal(table->write, row-size = 8, msg) 811 # . . push args 812 68/push "F - test-leaky-get-or-insert-slice/1"/imm32 813 68/push 8/imm32/row-size 814 ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . . # push *ecx 815 # . . call 816 e8/call check-ints-equal/disp32 817 # . . discard args 818 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 819 # check-strings-equal(*table->data, "code", msg) 820 # . . push args 821 68/push "F - test-leaky-get-or-insert-slice/2"/imm32 822 68/push "code"/imm32 823 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 0xc/disp8 . # push *(ecx+12) 824 # . . call 825 e8/call check-strings-equal/disp32 826 # . . discard args 827 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 828 $test-leaky-get-or-insert-slice:second-call: 829 # - insert the same key again, verify that it was reused 830 # eax = leaky-get-or-insert-slice(table, "code" slice, 8 bytes per row) 831 # . . push args 832 68/push 8/imm32/row-size 833 52/push-edx 834 51/push-ecx 835 # . . call 836 e8/call leaky-get-or-insert-slice/disp32 837 # . . discard args 838 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 839 # check-ints-equal(eax - table->data, 4, msg) 840 # . check-ints-equal(eax - table, 16, msg) 841 # . . push args 842 68/push "F - test-leaky-get-or-insert-slice/3"/imm32 843 68/push 0x10/imm32 844 29/subtract 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . . # subtract ecx from eax 845 50/push-eax 846 # . . call 847 e8/call check-ints-equal/disp32 848 # . . discard args 849 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 850 # no new row inserted 851 # . check-ints-equal(table->write, row-size = 8, msg) 852 # . . push args 853 68/push "F - test-leaky-get-or-insert-slice/4"/imm32 854 68/push 8/imm32/row-size 855 ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . . # push *ecx 856 # . . call 857 e8/call check-ints-equal/disp32 858 # . . discard args 859 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 860 # check-strings-equal(*table->data, "code", msg) 861 # . . push args 862 68/push "F - test-leaky-get-or-insert-slice/5"/imm32 863 68/push "code"/imm32 864 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 0xc/disp8 . # push *(ecx+12) 865 # . . call 866 e8/call check-strings-equal/disp32 867 # . . discard args 868 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 869 $test-leaky-get-or-insert-slice:third-call: 870 # - insert a new key, verify that it was inserted 871 # (eax..edx) = "data" 872 b8/copy-to-eax "data"/imm32 873 8b/copy 0/mod/indirect 0/rm32/eax . . . 2/r32/edx . . # copy *eax to edx 874 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 875 05/add-to-eax 4/imm32 876 # var slice/edx: slice = {eax, edx} 877 52/push-edx 878 50/push-eax 879 89/copy 3/mod/direct 2/rm32/edx . . . 4/r32/esp . . # copy esp to edx 880 # eax = leaky-get-or-insert-slice(table, "data" slice, 8 bytes per row) 881 # . . push args 882 68/push 8/imm32/row-size 883 52/push-edx 884 51/push-ecx 885 # . . call 886 e8/call leaky-get-or-insert-slice/disp32 887 # . . discard args 888 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 889 # table gets a new row 890 # check-ints-equal(eax - table->data, 12, msg) # second row's value slot returned 891 # . check-ints-equal(eax - table, 24, msg) 892 # . . push args 893 68/push "F - test-leaky-get-or-insert-slice/6"/imm32 894 68/push 0x18/imm32 895 29/subtract 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . . # subtract ecx from eax 896 50/push-eax 897 # . . call 898 e8/call check-ints-equal/disp32 899 # . . discard args 900 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 901 # check-ints-equal(table->write, 2 rows = 16, msg) 902 # . . push args 903 68/push "F - test-leaky-get-or-insert-slice/7"/imm32 904 68/push 0x10/imm32/two-rows 905 ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . . # push *ecx 906 # . . call 907 e8/call check-ints-equal/disp32 908 # . . discard args 909 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 910 # check-strings-equal(*table->data+8, "data", msg) 911 # check-strings-equal(*(table+20), "data", msg) 912 # . . push args 913 68/push "F - test-leaky-get-or-insert-slice/8"/imm32 914 68/push "data"/imm32 915 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 0x14/disp8 . # push *(ecx+20) 916 # . . call 917 e8/call check-strings-equal/disp32 918 # . . discard args 919 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 920 $test-leaky-get-or-insert-slice:end: 921 # . epilogue 922 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 923 5d/pop-to-ebp 924 c3/return 925 926 # if no row is found, stop(ed) 927 get-or-stop: # table: (addr stream {string_key, T}), key: string_key, row-size: int, 928 # abort-message-prefix: (addr array byte), err: (addr buffered-file), ed: (addr exit-descriptor) 929 # -> eax: (addr T) 930 # pseudocode: 931 # curr = table->data 932 # max = &table->data[table->write] 933 # while curr < max 934 # if string-equal?(key, *curr) 935 # return curr+4 936 # curr += row-size 937 # write-buffered(err, msg) 938 # stop(ed) 939 # 940 # . prologue 941 55/push-ebp 942 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 943 # . save registers 944 51/push-ecx 945 52/push-edx 946 56/push-esi 947 # esi = table 948 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 . # copy *(ebp+8) to esi 949 # var curr/ecx: (addr string_key) = table->data 950 8d/copy-address 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 0xc/disp8 . # copy esi+12 to ecx 951 # var max/edx: (addr byte) = &table->data[table->write] 952 8b/copy 0/mod/indirect 6/rm32/esi . . . 2/r32/edx . . # copy *esi to edx 953 8d/copy-address 0/mod/indirect 4/rm32/sib 1/base/ecx 2/index/edx . 2/r32/edx . . # copy ecx+edx to edx 954 $get-or-stop:search-loop: 955 # if (curr >= max) stop(ed) 956 39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx 957 73/jump-if-addr>= $get-or-stop:stop/disp8 958 # if (string-equal?(key, *curr)) return curr+4 959 # . eax = string-equal?(key, *curr) 960 # . . push args 961 ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . . # push *ecx 962 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) 963 # . . call 964 e8/call string-equal?/disp32 965 # . . discard args 966 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 967 # . if (eax != false) return eax = curr+4 968 3d/compare-eax-and 0/imm32/false 969 74/jump-if-= $get-or-stop:mismatch/disp8 970 8d/copy-address 1/mod/*+disp8 1/rm32/ecx . . . 0/r32/eax 4/disp8 . # copy ecx+4 to eax 971 eb/jump $get-or-stop:end/disp8 972 $get-or-stop:mismatch: 973 # curr += row-size 974 03/add 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 0x10/disp8 . # add *(ebp+16) to ecx 975 # loop 976 eb/jump $get-or-stop:search-loop/disp8 977 $get-or-stop:end: 978 # . restore registers 979 5e/pop-to-esi 980 5a/pop-to-edx 981 59/pop-to-ecx 982 # . epilogue 983 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 984 5d/pop-to-ebp 985 c3/return 986 987 $get-or-stop:stop: 988 # . write-buffered(err, abort-message-prefix) 989 # . . push args 990 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x14/disp8 . # push *(ebp+20) 991 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x18/disp8 . # push *(ebp+24) 992 # . . call 993 e8/call write-buffered/disp32 994 # . . discard args 995 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 996 # . write-buffered(err, error) 997 # . . push args 998 68/push ": get-or-stop: key not found: "/imm32 999 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x18/disp8 . # push *(ebp+24) 1000 # . . call 1001 e8/call write-buffered/disp32 1002 # . . discard args 1003 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1004 # . write-buffered(err, key) 1005 # . . push args 1006 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) 1007 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x18/disp8 . # push *(ebp+24) 1008 # . . call 1009 e8/call write-buffered/disp32 1010 # . . discard args 1011 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1012 # . write-buffered(err, "\n") 1013 # . . push args 1014 68/push Newline/imm32 1015 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x18/disp8 . # push *(ebp+24) 1016 # . . call 1017 e8/call write-buffered/disp32 1018 # . . discard args 1019 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1020 # . stop(ed, 1) 1021 # . . push args 1022 68/push 1/imm32 1023 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x1c/disp8 . # push *(ebp+28) 1024 # . . call 1025 e8/call stop/disp32 1026 # never gets here 1027 $get-or-stop:terminus: 1028 # . . discard args 1029 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1030 # syscall(exit, 1) 1031 b8/copy-to-eax 1/imm32/exit 1032 cd/syscall 0x80/imm8 1033 1034 test-get-or-stop: 1035 # This test uses exit-descriptors. Use ebp for setting up local variables. 1036 # . prologue 1037 55/push-ebp 1038 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 1039 # setup 1040 # . clear-stream(_test-error-stream) 1041 # . . push args 1042 68/push _test-error-stream/imm32 1043 # . . call 1044 e8/call clear-stream/disp32 1045 # . . discard args 1046 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1047 # . clear-stream($_test-error-buffered-file->buffer) 1048 # . . push args 1049 68/push $_test-error-buffered-file->buffer/imm32 1050 # . . call 1051 e8/call clear-stream/disp32 1052 # . . discard args 1053 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1054 # var table/ecx: (stream {string, number} 16) # 2 rows * 8 bytes/row 1055 81 5/subop/subtract 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # subtract from esp 1056 68/push 0x10/imm32/length 1057 68/push 0/imm32/read 1058 68/push 0/imm32/write 1059 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 1060 # var ed/edx: exit-descriptor 1061 68/push 0/imm32 1062 68/push 0/imm32 1063 89/copy 3/mod/direct 2/rm32/edx . . . 4/r32/esp . . # copy esp to edx 1064 # size 'ed' for the calls to 'get-or-stop' 1065 # . tailor-exit-descriptor(ed, 24) 1066 # . . push args 1067 68/push 0x18/imm32/nbytes-of-args-for-get-or-stop 1068 52/push-edx 1069 # . . call 1070 e8/call tailor-exit-descriptor/disp32 1071 # . . discard args 1072 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1073 # insert(table, "code", 8 bytes per row) 1074 # . . push args 1075 68/push 8/imm32/row-size 1076 68/push "code"/imm32 1077 51/push-ecx 1078 # . . call 1079 e8/call get-or-insert/disp32 1080 # . . discard args 1081 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1082 $test-get-or-stop:success: 1083 # eax = get-or-stop(table, "code", row-size=8, msg, _test-error-buffered-file, ed) 1084 # . . push args 1085 52/push-edx/ed 1086 68/push _test-error-buffered-file/imm32 1087 68/push "foo"/imm32/abort-prefix 1088 68/push 8/imm32/row-size 1089 68/push "code"/imm32 1090 51/push-ecx 1091 # . . call 1092 e8/call get-or-stop/disp32 1093 # . . discard args 1094 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x18/imm32 # add to esp 1095 $test-get-or-stop:success-assertion: 1096 # check-ints-equal(eax - table->data, 4, msg) 1097 # . check-ints-equal(eax - table, 16, msg) 1098 # . . push args 1099 68/push "F - test-get-or-stop/0"/imm32 1100 68/push 0x10/imm32 1101 29/subtract 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . . # subtract ecx from eax 1102 50/push-eax 1103 # . . call 1104 e8/call check-ints-equal/disp32 1105 # . . discard args 1106 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1107 $test-get-or-stop:failure: 1108 # eax = get-or-stop(table, "data", row-size=8, msg, _test-error-buffered-file, ed) 1109 # . . push args 1110 52/push-edx/ed 1111 68/push _test-error-buffered-file/imm32 1112 68/push "foo"/imm32/abort-prefix 1113 68/push 8/imm32/row-size 1114 68/push "data"/imm32 1115 51/push-ecx 1116 # . . call 1117 e8/call get-or-stop/disp32 1118 # registers except esp may be clobbered at this point 1119 # restore register args, discard others 1120 59/pop-to-ecx 1121 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp 1122 5a/pop-to-edx 1123 $test-get-or-stop:failure-assertion: 1124 # check that get-or-stop tried to call stop(1) 1125 # . check-ints-equal(ed->value, 2, msg) 1126 # . . push args 1127 68/push "F - test-get-or-stop/1"/imm32 1128 68/push 2/imm32 1129 # . . push ed->value 1130 ff 6/subop/push 1/mod/*+disp8 2/rm32/edx . . . . 4/disp8 . # push *(edx+4) 1131 # . . call 1132 e8/call check-ints-equal/disp32 1133 # . . discard args 1134 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1135 $test-get-or-stop:end: 1136 # . epilogue 1137 # don't restore esp from ebp; manually reclaim locals 1138 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x24/imm32 # add to esp 1139 5d/pop-to-ebp 1140 c3/return 1141 1142 # if no row is found, stop(ed) 1143 get-slice-or-stop: # table: (addr stream {string_key, _}), key: (addr slice), row-size: int, 1144 # abort-message-prefix: (addr string), err: (addr buffered-file), ed: (addr exit-descriptor) 1145 # -> eax: (addr _) 1146 # pseudocode: 1147 # curr = table->data 1148 # max = &table->data[table->write] 1149 # while curr < max 1150 # if slice-equal?(key, *curr) 1151 # return curr+4 1152 # curr += row-size 1153 # write-buffered(err, msg) 1154 # stop(ed) 1155 # 1156 # . prologue 1157 55/push-ebp 1158 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 1159 # . save registers 1160 51/push-ecx 1161 52/push-edx 1162 56/push-esi 1163 # esi = table 1164 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 . # copy *(ebp+8) to esi 1165 # var curr/ecx: (addr string_key) = table->data 1166 8d/copy-address 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 0xc/disp8 . # copy esi+12 to ecx 1167 # var max/edx: (addr byte) = &table->data[table->write] 1168 8b/copy 0/mod/indirect 6/rm32/esi . . . 2/r32/edx . . # copy *esi to edx 1169 8d/copy-address 0/mod/indirect 4/rm32/sib 1/base/ecx 2/index/edx . 2/r32/edx . . # copy ecx+edx to edx 1170 $get-slice-or-stop:search-loop: 1171 # if (curr >= max) stop(ed) 1172 39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx 1173 73/jump-if-addr>= $get-slice-or-stop:stop/disp8 1174 # if (slice-equal?(key, *curr)) return curr+4 1175 # . eax = slice-equal?(key, *curr) 1176 # . . push args 1177 ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . . # push *ecx 1178 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) 1179 # . . call 1180 e8/call slice-equal?/disp32 1181 # . . discard args 1182 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1183 # . if (eax != false) return eax = curr+4 1184 3d/compare-eax-and 0/imm32/false 1185 74/jump-if-= $get-slice-or-stop:mismatch/disp8 1186 8d/copy-address 1/mod/*+disp8 1/rm32/ecx . . . 0/r32/eax 4/disp8 . # copy ecx+4 to eax 1187 eb/jump $get-slice-or-stop:end/disp8 1188 $get-slice-or-stop:mismatch: 1189 # curr += row-size 1190 03/add 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 0x10/disp8 . # add *(ebp+16) to ecx 1191 # loop 1192 eb/jump $get-slice-or-stop:search-loop/disp8 1193 $get-slice-or-stop:end: 1194 # . restore registers 1195 5e/pop-to-esi 1196 5a/pop-to-edx 1197 59/pop-to-ecx 1198 # . epilogue 1199 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 1200 5d/pop-to-ebp 1201 c3/return 1202 1203 $get-slice-or-stop:stop: 1204 # . write-buffered(err, abort-message-prefix) 1205 # . . push args 1206 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x14/disp8 . # push *(ebp+20) 1207 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x18/disp8 . # push *(ebp+24) 1208 # . . call 1209 e8/call write-buffered/disp32 1210 # . . discard args 1211 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1212 # . write-buffered(err, error) 1213 # . . push args 1214 68/push ": get-slice-or-stop: key not found: "/imm32 1215 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x18/disp8 . # push *(ebp+24) 1216 # . . call 1217 e8/call write-buffered/disp32 1218 # . . discard args 1219 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1220 # . write-slice-buffered(err, key) 1221 # . . push args 1222 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) 1223 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x18/disp8 . # push *(ebp+24) 1224 # . . call 1225 e8/call write-slice-buffered/disp32 1226 # . . discard args 1227 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1228 # . write-buffered(err, "\n") 1229 # . . push args 1230 68/push Newline/imm32 1231 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x18/disp8 . # push *(ebp+24) 1232 # . . call 1233 e8/call write-buffered/disp32 1234 # . . discard args 1235 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1236 # . stop(ed, 1) 1237 # . . push args 1238 68/push 1/imm32 1239 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x1c/disp8 . # push *(ebp+28) 1240 # . . call 1241 e8/call stop/disp32 1242 # never gets here 1243 $get-slice-or-stop:terminus: 1244 # . . discard args 1245 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1246 # syscall(exit, 1) 1247 b8/copy-to-eax 1/imm32/exit 1248 cd/syscall 0x80/imm8 1249 1250 test-get-slice-or-stop: 1251 # This test uses exit-descriptors. Use ebp for setting up local variables. 1252 # . prologue 1253 55/push-ebp 1254 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 1255 # setup 1256 # . clear-stream(_test-error-stream) 1257 # . . push args 1258 68/push _test-error-stream/imm32 1259 # . . call 1260 e8/call clear-stream/disp32 1261 # . . discard args 1262 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1263 # . clear-stream($_test-error-buffered-file->buffer) 1264 # . . push args 1265 68/push $_test-error-buffered-file->buffer/imm32 1266 # . . call 1267 e8/call clear-stream/disp32 1268 # . . discard args 1269 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1270 # var table/ecx: (stream {string, number} 16) # 2 rows * 8 bytes/row 1271 81 5/subop/subtract 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # subtract from esp 1272 68/push 0x10/imm32/length 1273 68/push 0/imm32/read 1274 68/push 0/imm32/write 1275 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 1276 # var ed/edx: exit-descriptor 1277 68/push 0/imm32 1278 68/push 0/imm32 1279 89/copy 3/mod/direct 2/rm32/edx . . . 4/r32/esp . . # copy esp to edx 1280 # var slice/ebx: slice = "code" 1281 # . (eax..ebx) = "code" 1282 b8/copy-to-eax "code"/imm32 1283 8b/copy 0/mod/indirect 0/rm32/eax . . . 3/r32/ebx . . # copy *eax to ebx 1284 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 1285 05/add-to-eax 4/imm32 1286 # . ebx = {eax, ebx} 1287 53/push-ebx 1288 50/push-eax 1289 89/copy 3/mod/direct 3/rm32/ebx . . . 4/r32/esp . . # copy esp to ebx 1290 # size 'ed' for the calls to 'get-or-stop' (define no locals past this point) 1291 # . tailor-exit-descriptor(ed, 24) 1292 # . . push args 1293 68/push 0x18/imm32/nbytes-of-args-for-get-or-stop 1294 52/push-edx 1295 # . . call 1296 e8/call tailor-exit-descriptor/disp32 1297 # . . discard args 1298 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1299 # insert(table, "code", 8 bytes per row) 1300 # . . push args 1301 68/push 8/imm32/row-size 1302 68/push "code"/imm32 1303 51/push-ecx 1304 # . . call 1305 e8/call get-or-insert/disp32 1306 # . . discard args 1307 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1308 $test-get-slice-or-stop:success: 1309 # eax = get-slice-or-stop(table, slice, row-size=8, msg, _test-error-buffered-file, ed) 1310 # . . push args 1311 52/push-edx/ed 1312 68/push _test-error-buffered-file/imm32 1313 68/push "foo"/imm32/abort-prefix 1314 68/push 8/imm32/row-size 1315 53/push-ebx/slice 1316 51/push-ecx 1317 # . . call 1318 e8/call get-slice-or-stop/disp32 1319 # registers except esp may be clobbered at this point 1320 # restore register args, discard others 1321 59/pop-to-ecx 1322 5b/pop-to-ebx 1323 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1324 5a/pop-to-edx 1325 $test-get-slice-or-stop:success-assertion: 1326 # check-ints-equal(eax - table->data, 4, msg) # first row's value slot returned 1327 # . check-ints-equal(eax - table, 16, msg) 1328 # . . push args 1329 68/push "F - test-get-slice-or-stop/0"/imm32 1330 68/push 0x10/imm32 1331 29/subtract 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . . # subtract ecx from eax 1332 50/push-eax 1333 # . . call 1334 e8/call check-ints-equal/disp32 1335 # . . discard args 1336 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1337 $test-get-slice-or-stop:failure: 1338 # slice = "segment2" 1339 # . *ebx = "segment2"->data 1340 b8/copy-to-eax "segment2"/imm32 1341 05/add-to-eax 4/imm32 1342 89/copy 0/mod/indirect 3/rm32/ebx . . . 0/r32/eax . . # copy eax to *ebx 1343 # . *(ebx+4) = "segment2"->data + len("segment2") 1344 05/add-to-eax 8/imm32/strlen 1345 89/copy 1/mod/*+disp8 3/rm32/ebx . . . 0/r32/eax 4/disp8 . # copy eax to *(ebx+4) 1346 # eax = get-slice-or-stop(table, slice, row-size=8, msg, _test-error-buffered-file, ed) 1347 # . . push args 1348 52/push-edx/ed 1349 68/push _test-error-buffered-file/imm32 1350 68/push "foo"/imm32/abort-prefix 1351 68/push 8/imm32/row-size 1352 53/push-ebx/slice 1353 51/push-ecx 1354 # . . call 1355 e8/call get-slice-or-stop/disp32 1356 # registers except esp may be clobbered at this point 1357 # restore register args, discard others 1358 59/pop-to-ecx 1359 5b/pop-to-ebx 1360 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1361 5a/pop-to-edx 1362 $test-get-slice-or-stop:failure-assertion: 1363 # check that get-or-stop tried to call stop(1) 1364 # . check-ints-equal(ed->value, 2, msg) 1365 # . . push args 1366 68/push "F - test-get-or-stop/1"/imm32 1367 68/push 2/imm32 1368 # . . push ed->value 1369 ff 6/subop/push 1/mod/*+disp8 2/rm32/edx . . . . 4/disp8 . # push *(edx+4) 1370 # . . call 1371 e8/call check-ints-equal/disp32 1372 # . . discard args 1373 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1374 $test-get-slice-or-stop:end: 1375 # . epilogue 1376 # don't restore esp from ebp; manually reclaim locals 1377 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x2c/imm32 # add to esp 1378 5d/pop-to-ebp 1379 c3/return 1380 1381 # if no row is found, return null (0) 1382 maybe-get: # table: (addr stream {string_key, T}), key: string_key, row-size: int -> eax: (addr T) 1383 # pseudocode: 1384 # curr = table->data 1385 # max = &table->data[table->write] 1386 # while curr < max 1387 # if string-equal?(key, *curr) 1388 # return curr+4 1389 # curr += row-size 1390 # return 0 1391 # 1392 # . prologue 1393 55/push-ebp 1394 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 1395 # . save registers 1396 51/push-ecx 1397 52/push-edx 1398 56/push-esi 1399 # esi = table 1400 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 . # copy *(ebp+8) to esi 1401 # var curr/ecx: (addr string_key) = table->data 1402 8d/copy-address 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 0xc/disp8 . # copy esi+12 to ecx 1403 # var max/edx: (addr byte) = &table->data[table->write] 1404 8b/copy 0/mod/indirect 6/rm32/esi . . . 2/r32/edx . . # copy *esi to edx 1405 8d/copy-address 0/mod/indirect 4/rm32/sib 1/base/ecx 2/index/edx . 2/r32/edx . . # copy ecx+edx to edx 1406 $maybe-get:search-loop: 1407 # if (curr >= max) return null 1408 39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx 1409 73/jump-if-addr>= $maybe-get:null/disp8 1410 # if (string-equal?(key, *curr)) return curr+4 1411 # . eax = string-equal?(key, *curr) 1412 # . . push args 1413 ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . . # push *ecx 1414 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) 1415 # . . call 1416 e8/call string-equal?/disp32 1417 # . . discard args 1418 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1419 # . if (eax != false) return eax = curr+4 1420 3d/compare-eax-and 0/imm32/false 1421 74/jump-if-= $maybe-get:mismatch/disp8 1422 8d/copy-address 1/mod/*+disp8 1/rm32/ecx . . . 0/r32/eax 4/disp8 . # copy ecx+4 to eax 1423 eb/jump $maybe-get:end/disp8 1424 $maybe-get:mismatch: 1425 # curr += row-size 1426 03/add 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 0x10/disp8 . # add *(ebp+16) to ecx 1427 # loop 1428 eb/jump $maybe-get:search-loop/disp8 1429 $maybe-get:null: 1430 b8/copy-to-eax 0/imm32 1431 $maybe-get:end: 1432 # . restore registers 1433 5e/pop-to-esi 1434 5a/pop-to-edx 1435 59/pop-to-ecx 1436 # . epilogue 1437 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 1438 5d/pop-to-ebp 1439 c3/return 1440 1441 test-maybe-get: 1442 # . prologue 1443 55/push-ebp 1444 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 1445 # - setup: create a table with one row 1446 # var table/ecx: (stream {string, number} 16) # 2 rows * 8 bytes/row 1447 81 5/subop/subtract 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # subtract from esp 1448 68/push 0x10/imm32/length 1449 68/push 0/imm32/read 1450 68/push 0/imm32/write 1451 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 1452 # eax = get-or-insert(table, "code", 8 bytes per row) 1453 # . . push args 1454 68/push 8/imm32/row-size 1455 68/push "code"/imm32 1456 51/push-ecx 1457 # . . call 1458 e8/call get-or-insert/disp32 1459 # . . discard args 1460 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1461 $test-maybe-get:success: 1462 # - check for the same key, verify that it was reused 1463 # eax = maybe-get(table, "code", 8 bytes per row) 1464 # . . push args 1465 68/push 8/imm32/row-size 1466 68/push "code"/imm32 1467 51/push-ecx 1468 # . . call 1469 e8/call maybe-get/disp32 1470 # . . discard args 1471 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1472 # check-ints-equal(eax - table->data, 4, msg) 1473 # . check-ints-equal(eax - table, 16, msg) 1474 # . . push args 1475 68/push "F - test-maybe-get/0"/imm32 1476 68/push 0x10/imm32 1477 29/subtract 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . . # subtract ecx from eax 1478 50/push-eax 1479 # . . call 1480 e8/call check-ints-equal/disp32 1481 # . . discard args 1482 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1483 # no new row inserted 1484 # . check-ints-equal(table->write, row-size = 8, msg) 1485 # . . push args 1486 68/push "F - test-maybe-get/1"/imm32 1487 68/push 8/imm32/row-size 1488 ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . . # push *ecx 1489 # . . call 1490 e8/call check-ints-equal/disp32 1491 # . . discard args 1492 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1493 # check-strings-equal(*table->data, "code", msg) 1494 # . . push args 1495 68/push "F - test-maybe-get/2"/imm32 1496 68/push "code"/imm32 1497 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 0xc/disp8 . # push *(ecx+12) 1498 # . . call 1499 e8/call check-strings-equal/disp32 1500 # . . discard args 1501 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1502 $test-maybe-get:failure: 1503 # - search for a new key 1504 # eax = maybe-get(table, "data", 8 bytes per row) 1505 # . . push args 1506 68/push 8/imm32/row-size 1507 68/push "data"/imm32 1508 51/push-ecx 1509 # . . call 1510 e8/call maybe-get/disp32 1511 # . . discard args 1512 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1513 # check-ints-equal(eax, 0, msg) 1514 # . . push args 1515 68/push "F - test-maybe-get/3"/imm32 1516 68/push 0/imm32 1517 50/push-eax 1518 # . . call 1519 e8/call check-ints-equal/disp32 1520 # . . discard args 1521 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1522 $test-maybe-get:end: 1523 # . epilogue 1524 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 1525 5d/pop-to-ebp 1526 c3/return 1527 1528 # if no row is found, return null (0) 1529 maybe-get-slice: # table: (addr stream {string_key, T}), key: (addr slice), row-size: int -> eax: (addr T) 1530 # pseudocode: 1531 # curr = table->data 1532 # max = &table->data[table->write] 1533 # while curr < max 1534 # if slice-equal?(key, *curr) 1535 # return curr+4 1536 # curr += row-size 1537 # return 0 1538 # 1539 # . prologue 1540 55/push-ebp 1541 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 1542 # . save registers 1543 51/push-ecx 1544 52/push-edx 1545 56/push-esi 1546 # esi = table 1547 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 . # copy *(ebp+8) to esi 1548 # var curr/ecx: (addr string_key) = table->data 1549 8d/copy-address 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 0xc/disp8 . # copy esi+12 to ecx 1550 # var max/edx: (addr byte) = &table->data[table->write] 1551 8b/copy 0/mod/indirect 6/rm32/esi . . . 2/r32/edx . . # copy *esi to edx 1552 8d/copy-address 0/mod/indirect 4/rm32/sib 1/base/ecx 2/index/edx . 2/r32/edx . . # copy ecx+edx to edx 1553 $maybe-get-slice:search-loop: 1554 # if (curr >= max) return null 1555 39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx 1556 73/jump-if-addr>= $maybe-get-slice:null/disp8 1557 # if (slice-equal?(key, *curr)) return curr+4 1558 # . eax = slice-equal?(key, *curr) 1559 # . . push args 1560 ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . . # push *ecx 1561 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) 1562 # . . call 1563 e8/call slice-equal?/disp32 1564 # . . discard args 1565 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1566 # . if (eax != false) return eax = curr+4 1567 3d/compare-eax-and 0/imm32/false 1568 74/jump-if-= $maybe-get-slice:mismatch/disp8 1569 8d/copy-address 1/mod/*+disp8 1/rm32/ecx . . . 0/r32/eax 4/disp8 . # copy ecx+4 to eax 1570 eb/jump $maybe-get-slice:end/disp8 1571 $maybe-get-slice:mismatch: 1572 # curr += row-size 1573 03/add 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 0x10/disp8 . # add *(ebp+16) to ecx 1574 # loop 1575 eb/jump $maybe-get-slice:search-loop/disp8 1576 $maybe-get-slice:null: 1577 b8/copy-to-eax 0/imm32 1578 $maybe-get-slice:end: 1579 # . restore registers 1580 5e/pop-to-esi 1581 5a/pop-to-edx 1582 59/pop-to-ecx 1583 # . epilogue 1584 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 1585 5d/pop-to-ebp 1586 c3/return 1587 1588 test-maybe-get-slice: 1589 # . prologue 1590 55/push-ebp 1591 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 1592 # - setup: create a table with one row 1593 # var table/ecx: (stream {string, number} 16) # 2 rows * 8 bytes/row 1594 81 5/subop/subtract 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # subtract from esp 1595 68/push 0x10/imm32/length 1596 68/push 0/imm32/read 1597 68/push 0/imm32/write 1598 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 1599 # insert(table, "code", 8 bytes per row) 1600 # . . push args 1601 68/push 8/imm32/row-size 1602 68/push "code"/imm32 1603 51/push-ecx 1604 # . . call 1605 e8/call get-or-insert/disp32 1606 # . . discard args 1607 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1608 $test-maybe-get-slice:success: 1609 # - check for the same key, verify that it was reused 1610 # (eax..edx) = "code" 1611 b8/copy-to-eax "code"/imm32 1612 8b/copy 0/mod/indirect 0/rm32/eax . . . 2/r32/edx . . # copy *eax to edx 1613 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 1614 05/add-to-eax 4/imm32 1615 # var slice/edx: slice = {eax, edx} 1616 52/push-edx 1617 50/push-eax 1618 89/copy 3/mod/direct 2/rm32/edx . . . 4/r32/esp . . # copy esp to edx 1619 # eax = maybe-get-slice(table, "code" slice, 8 bytes per row) 1620 # . . push args 1621 68/push 8/imm32/row-size 1622 52/push-edx 1623 51/push-ecx 1624 # . . call 1625 e8/call maybe-get-slice/disp32 1626 # . . discard args 1627 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1628 # check-ints-equal(eax - table->data, 4, msg) 1629 # . check-ints-equal(eax - table, 16, msg) 1630 # . . push args 1631 68/push "F - test-maybe-get-slice/0"/imm32 1632 68/push 0x10/imm32 1633 29/subtract 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . . # subtract ecx from eax 1634 50/push-eax 1635 # . . call 1636 e8/call check-ints-equal/disp32 1637 # . . discard args 1638 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1639 # no new row inserted 1640 # . check-ints-equal(table->write, row-size = 8, msg) 1641 # . . push args 1642 68/push "F - test-maybe-get-slice/1"/imm32 1643 68/push 8/imm32/row-size 1644 ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . . # push *ecx 1645 # . . call 1646 e8/call check-ints-equal/disp32 1647 # . . discard args 1648 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1649 # check-strings-equal(*table->data, "code", msg) 1650 # . . push args 1651 68/push "F - test-maybe-get-slice/2"/imm32 1652 68/push "code"/imm32 1653 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 0xc/disp8 . # push *(ecx+12) 1654 # . . call 1655 e8/call check-strings-equal/disp32 1656 # . . discard args 1657 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1658 $test-maybe-get-slice:failure: 1659 # - search for a new key 1660 # (eax..edx) = "data" 1661 b8/copy-to-eax "data"/imm32 1662 8b/copy 0/mod/indirect 0/rm32/eax . . . 2/r32/edx . . # copy *eax to edx 1663 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 1664 05/add-to-eax 4/imm32 1665 # var slice/edx: slice = {eax, edx} 1666 52/push-edx 1667 50/push-eax 1668 89/copy 3/mod/direct 2/rm32/edx . . . 4/r32/esp . . # copy esp to edx 1669 # eax = maybe-get-slice(table, "data" slice, 8 bytes per row) 1670 # . . push args 1671 68/push 8/imm32/row-size 1672 52/push-edx 1673 51/push-ecx 1674 # . . call 1675 e8/call maybe-get-slice/disp32 1676 # . . discard args 1677 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1678 # check-ints-equal(eax, 0, msg) 1679 # . . push args 1680 68/push "F - test-maybe-get-slice/3"/imm32 1681 68/push 0/imm32 1682 50/push-eax 1683 # . . call 1684 e8/call check-ints-equal/disp32 1685 # . . discard args 1686 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1687 $test-maybe-get-slice:end: 1688 # . epilogue 1689 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 1690 5d/pop-to-ebp 1691 c3/return 1692 1693 # . . vim:nowrap:textwidth=0