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-sizepre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>Mu - 086scenario_console_test.mu</title>
<meta name="Generator" content="Vim/8.0">
<meta name="plugin-version" content="vim7.4_v2">
<meta name="syntax" content="none">
<meta name="settings" content="number_lines,use_css,pre_wrap,no_foldcolumn,expand_tabs,line_ids,prevent_copy=">
<meta name="colorscheme" content="minimal">
<style type="text/css">
<!--
pre { white-space: pre-wrap; font-family: monospace; color: #aaaaaa; background-color: #080808; }
body { font-size:12pt; font-family: monospace; color: #aaaaaa; background-color: #080808; }
.subxS2Comment a { color:inherit; }
.subxS1Comment a { color:inherit; }
.subxComment a { color:inherit; }
.subxH2Comment a { color:inherit; }
.subxH1Comment a { color:inherit; }
* { font-size:12pt; font-size: 1em; }
.muScenario { color: #00af00; }
.LineNr { color:#444444; }
.Constant { color:#00a0a0; }
.Special { color:#c00000; }
.Comment { color: #8080ff; }
-->
</style>

<script type='text/javascript'>
<!--

/* function to open any folds containing a jumped-to line before jumping to it */
function JumpToLine()
{
  var lineNum;
  lineNum = window.location.hash;
  lineNum = lineNum.substr(1); /* strip off '#' */

  if (lineNum.indexOf('L') == -1) {
    lineNum = 'L'+lineNum;
  }
  lineElem = document.getElementById(lineNum);
  /* Always jump to new location even if the line was hidden inside a fold, or
   * we corrected the raw number to a line ID.
   */
  if (lineElem) {
    lineElem.scrollIntoView(true);
  }
  return true;
}
if ('onhashchange' in window) {
  window.onhashchange = JumpToLine;
}

-->
</script>
</head>
<body onload='JumpToLine();'>
<a href='https://github.com/akkartik/mu/blob/master/086scenario_console_test.mu'>https://github.com/akkartik/mu/blob/master/086scenario_console_test.mu</a>
<pre id='vimCodeElement'>
<span id="L1" class="LineNr"> 1 </span><span class="Comment"># To check our support for consoles in scenarios, rewrite tests from</span>
<span id="L2" class="LineNr"> 2 </span><span class="Comment"># scenario_console.mu</span>
<span id="L3" class="LineNr"> 3 </span><span class="Comment"># Tests for console interface.</span>
<span id="L4" class="LineNr"> 4 </span>
<span id="L5" class="LineNr"> 5 </span><span class="muScenario">scenario</span> read-key-in-mu [
<span id="L6" class="LineNr"> 6 </span>  assume-console [
<span id="L7" class="LineNr"> 7 </span>    type <span class="Constant">[abc]</span>
<span id="L8" class="LineNr"> 8 </span>  ]
<span id="L9" class="LineNr"> 9 </span>  run [
<span id="L10" class="LineNr">10 </span>    1:char, 2:bool <span class="Special">&lt;-</span> <a href='084console.mu.html#L62'>read-key</a> <a href='084console.mu.html#L23'>console</a>
<span id="L11" class="LineNr">11 </span>    3:char, 4:bool <span class="Special">&lt;-</span> <a href='084console.mu.html#L62'>read-key</a> <a href='084console.mu.html#L23'>console</a>
<span id="L12" class="LineNr">12 </span>    5:char, 6:bool <span class="Special">&lt;-</span> <a href='084console.mu.html#L62'>read-key</a> <a href='084console.mu.html#L23'>console</a>
<span id="L13" class="LineNr">13 </span>    7:char, 8:bool <span class="Special">&lt;-</span> <a href='084console.mu.html#L62'>read-key</a> <a href='084console.mu.html#L23'>console</a>
<span id="L14" class="LineNr">14 </span>  ]
<span id="L15" class="LineNr">15 </span>  memory-should-contain [
<span id="L16" class="LineNr">16 </span>   <span class="Constant"> 1</span> <span class="Special">&lt;-</span><span class="Constant"> 97</span>  <span class="Comment"># 'a'</span>
<span id="L17" class="LineNr">17 </span>   <span class="Constant"> 2</span> <span class="Special">&lt;-</span><span class="Constant"> 1</span>
<span id="L18" class="LineNr">18 </span>   <span class="Constant"> 3</span> <span class="Special">&lt;-</span><span class="Constant"> 98</span>  <span class="Comment"># 'b'</span>
<span id="L19" class="LineNr">19 </span>   <span class="Constant"> 4</span> <span class="Special">&lt;-</span><span class="Constant"> 1</span>
<span id="L20" class="LineNr">20 </span>   <span class="Constant"> 5</span> <span class="Special">&lt;-</span><span class="Constant"> 99</span>  <span class="Comment"># 'c'</span>
<span id="L21" class="LineNr">21 </span>   <span class="Constant"> 6</span> <span class="Special">&lt;-</span><span class="Constant"> 1</span>
<span id="L22" class="LineNr">22 </span>   <span class="Constant"> 7</span> <span class="Special">&lt;-</span><span class="Constant"> 0</span>  <span class="Comment"># eof</span>
<span id="L23" class="LineNr">23 </span>   <span class="Constant"> 8</span> <span class="Special">&lt;-</span><span class="Constant"> 1</span>
<span id="L24" class="LineNr">24 </span>  ]
<span id="L25" class="LineNr">25 </span>]
</pre>
</body>
</html>
<!-- vim: set foldmethod=manual : -->
/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 # save 'key' to the next available row 704 # if key already exists, abort 705 # if there are no rows free, abort 706 # return the address of the value 707 insert-or-abort: # table: (addr stream {(handle array byte), T}), key: (addr array byte), row-size: int, ad: (addr allocation-descriptor) -> result/eax: (addr T) 708 # pseudocode: 709 # curr = table->data 710 # max = &table->data[table->write] 711 # while curr < max 712 # var c: (addr array byte) = lookup(*curr) 713 # if string-equal?(key, c) 714 # abort 715 # curr += row-size 716 # if table->write >= table->size 717 # abort 718 # zero-out(max, row-size) 719 # copy-array(ad, key, max) 720 # table->write += row-size 721 # return max+8 722 # 723 # . prologue 724 55/push-ebp 725 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 726 # . save registers 727 51/push-ecx 728 52/push-edx 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 curr/ecx: (addr handle array byte) = table->data 733 8d/copy-address 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 0xc/disp8 . # copy esi+12 to ecx 734 # var max/edx: (addr byte) = &table->data[table->write] 735 8b/copy 0/mod/indirect 6/rm32/esi . . . 2/r32/edx . . # copy *esi to edx 736 8d/copy-address 0/mod/indirect 4/rm32/sib 1/base/ecx 2/index/edx . 2/r32/edx . . # copy ecx+edx to edx 737 $insert-or-abort:search-loop: 738 # if (curr >= max) break 739 39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx 740 73/jump-if-addr>= $insert-or-abort:not-found/disp8 741 # var c/eax: (addr array byte) = lookup(*curr) 742 # . . push args 743 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 4/disp8 . # push *(ecx+4) 744 ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . . # push *ecx 745 # . . call 746 e8/call lookup/disp32 747 # . . discard args 748 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 749 # if (string-equal?(key, c)) abort 750 # . eax = string-equal?(key, c) 751 # . . push args 752 50/push-eax 753 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) 754 # . . call 755 e8/call string-equal?/disp32 756 # . . discard args 757 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 758 # . if (eax != false) abort 759 3d/compare-eax-and 0/imm32/false 760 0f 85/jump-if-!= $insert-or-abort:error-duplicate/disp32 761 # curr += row-size 762 03/add 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 0x10/disp8 . # add *(ebp+16) to ecx 763 # loop 764 eb/jump $insert-or-abort:search-loop/disp8 765 $insert-or-abort:not-found: 766 # if (table->write >= table->size) abort 767 8b/copy 0/mod/indirect 6/rm32/esi . . . 1/r32/ecx . . # copy *esi to ecx 768 3b/compare 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 8/disp8 . # compare ecx with *(esi+8) 769 0f 83/jump-if-addr>= $insert-or-abort:error-full/disp32 770 # zero-out(max, row-size) 771 # . . push args 772 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x10/disp8 . # push *(ebp+16) 773 52/push-edx 774 # . . call 775 e8/call zero-out/disp32 776 # . . discard args 777 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 778 # copy-array(ad, key, max) 779 # . . push args 780 52/push-edx 781 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) 782 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x14/disp8 . # push *(ebp+20) 783 # . . call 784 e8/call copy-array/disp32 785 # . . discard args 786 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 787 # table->write += row-size 788 # . eax = row-size 789 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 0x10/disp8 . # copy *(ebp+16) to eax 790 # . table->write += eax 791 01/add 0/mod/indirect 6/rm32/esi . . . 0/r32/eax . . # add eax to *esi 792 # return max+8 793 # . eax = max 794 89/copy 3/mod/direct 0/rm32/eax . . . 2/r32/edx . . # copy edx to eax 795 # . eax += 8 796 05/add-to-eax 8/imm32 797 $insert-or-abort:end: 798 # . restore registers 799 5e/pop-to-esi 800 5a/pop-to-edx 801 59/pop-to-ecx 802 # . epilogue 803 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 804 5d/pop-to-ebp 805 c3/return 806 807 $insert-or-abort:error-duplicate: 808 # . _write(2/stderr, error) 809 # . . push args 810 68/push "insert-or-abort: key already exists: "/imm32 811 68/push 2/imm32/stderr 812 # . . call 813 e8/call _write/disp32 814 # . . discard args 815 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 816 # . _write(2/stderr, key) 817 # . . push args 818 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) 819 68/push 2/imm32/stderr 820 # . . call 821 e8/call _write/disp32 822 # . . discard args 823 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 824 # . _write(2/stderr, "\n") 825 # . . push args 826 68/push "\n"/imm32 827 68/push 2/imm32/stderr 828 # . . call 829 e8/call _write/disp32 830 # . . discard args 831 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 832 # . syscall_exit(1) 833 bb/copy-to-ebx 1/imm32 834 e8/call syscall_exit/disp32 835 # never gets here 836 837 $insert-or-abort:error-full: 838 # . _write(2/stderr, error) 839 # . . push args 840 68/push "insert-or-abort: table is full\n"/imm32 841 68/push 2/imm32/stderr 842 # . . call 843 e8/call _write/disp32 844 # . . discard args 845 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 846 # . syscall_exit(1) 847 bb/copy-to-ebx 1/imm32 848 e8/call syscall_exit/disp32 849 # never gets here 850 851 # if no row is found, save 'key' to the next available row 852 # if there are no rows free, abort 853 # return the address of the value 854 get-or-insert-handle: # table: (addr stream {(handle array byte), T}), key: (handle array byte), row-size: int -> result/eax: (addr T) 855 # pseudocode: 856 # var curr: (addr handle stream) = table->data 857 # var max: (addr byte) = &table->data[table->write] 858 # var k: (addr array byte) = lookup(key) 859 # while curr < max 860 # var c: (addr array byte) = lookup(*curr) 861 # if string-equal?(k, c) 862 # return curr+8 863 # curr += row-size 864 # if table->write >= table->size 865 # abort 866 # *max = key 867 # table->write += row-size 868 # return max+8 869 # 870 # . prologue 871 55/push-ebp 872 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 873 # . save registers 874 51/push-ecx 875 52/push-edx 876 53/push-ebx 877 56/push-esi 878 # esi = table 879 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 . # copy *(ebp+8) to esi 880 # var k/ebx: (addr array byte) = lookup(key) 881 # . eax = lookup(key) 882 # . . push args 883 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x10/disp8 . # push *(ebp+16) 884 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) 885 # . . call 886 e8/call lookup/disp32 887 # . . discard args 888 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 889 # . ebx = eax 890 89/copy 3/mod/direct 3/rm32/ebx . . . 0/r32/eax . . # copy eax to ebx 891 # var curr/ecx: (addr handle array byte) = table->data 892 8d/copy-address 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 0xc/disp8 . # copy esi+12 to ecx 893 # var max/edx: (addr byte) = &table->data[table->write] 894 8b/copy 0/mod/indirect 6/rm32/esi . . . 2/r32/edx . . # copy *esi to edx 895 8d/copy-address 0/mod/indirect 4/rm32/sib 1/base/ecx 2/index/edx . 2/r32/edx . . # copy ecx+edx to edx 896 $get-or-insert-handle:search-loop: 897 # if (curr >= max) break 898 39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx 899 73/jump-if-addr>= $get-or-insert-handle:not-found/disp8 900 # var c/eax: (addr array byte) = lookup(*curr) 901 # . . push args 902 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 4/disp8 . # push *(ecx+4) 903 ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . . # push *ecx 904 # . . call 905 e8/call lookup/disp32 906 # . . discard args 907 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 908 # if (string-equal?(k, c)) return curr+8 909 # . eax = string-equal?(k, c) 910 # . . push args 911 50/push-eax 912 53/push-ebx 913 # . . call 914 e8/call string-equal?/disp32 915 # . . discard args 916 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 917 # . if (eax != false) return eax = curr+8 918 3d/compare-eax-and 0/imm32/false 919 74/jump-if-= $get-or-insert-handle:mismatch/disp8 920 8d/copy-address 1/mod/*+disp8 1/rm32/ecx . . . 0/r32/eax 8/disp8 . # copy ecx+8 to eax 921 eb/jump $get-or-insert-handle:end/disp8 922 $get-or-insert-handle:mismatch: 923 # curr += row-size 924 03/add 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 0x14/disp8 . # add *(ebp+20) to ecx 925 # loop 926 eb/jump $get-or-insert-handle:search-loop/disp8 927 $get-or-insert-handle:not-found: 928 # if (table->write >= table->size) abort 929 8b/copy 0/mod/indirect 6/rm32/esi . . . 1/r32/ecx . . # copy *esi to ecx 930 3b/compare 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 8/disp8 . # compare ecx with *(esi+8) 931 73/jump-if-addr>= $get-or-insert-handle:abort/disp8 932 # table->write += row-size 933 # . eax = row-size 934 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 0x14/disp8 . # copy *(ebp+20) to eax 935 # . table->write += eax 936 01/add 0/mod/indirect 6/rm32/esi . . . 0/r32/eax . . # add eax to *esi 937 # *max = key 938 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 0xc/disp8 . # copy *(ebp+12) to eax 939 89/copy 0/mod/indirect 2/rm32/edx . . . 0/r32/eax . . # copy eax to *edx 940 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 0x10/disp8 . # copy *(ebp+16) to eax 941 89/copy 1/mod/*+disp8 2/rm32/edx . . . 0/r32/eax 4/disp8 . # copy eax to *(edx+4) 942 # return max+8 943 # . eax = max 944 89/copy 3/mod/direct 0/rm32/eax . . . 2/r32/edx . . # copy edx to eax 945 # . eax += 8 946 05/add-to-eax 8/imm32 947 $get-or-insert-handle:end: 948 # . restore registers 949 5e/pop-to-esi 950 5b/pop-to-ebx 951 5a/pop-to-edx 952 59/pop-to-ecx 953 # . epilogue 954 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 955 5d/pop-to-ebp 956 c3/return 957 958 $get-or-insert-handle:abort: 959 # . _write(2/stderr, error) 960 # . . push args 961 68/push "get-or-insert-handle: table is full\n"/imm32 962 68/push 2/imm32/stderr 963 # . . call 964 e8/call _write/disp32 965 # . . discard args 966 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 967 # . syscall_exit(1) 968 bb/copy-to-ebx 1/imm32 969 e8/call syscall_exit/disp32 970 # never gets here 971 972 test-get-or-insert-handle: 973 # . prologue 974 55/push-ebp 975 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 976 # var table/ecx: (stream {(handle array byte), number} 24) # 2 rows * 12 bytes/row 977 81 5/subop/subtract 3/mod/direct 4/rm32/esp . . . . . 0x18/imm32 # subtract from esp 978 68/push 0x18/imm32/size 979 68/push 0/imm32/read 980 68/push 0/imm32/write 981 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 982 # var h/edx: (handle array byte) 983 68/push 0/imm32 984 68/push 0/imm32 985 89/copy 3/mod/direct 2/rm32/edx . . . 4/r32/esp . . # copy esp to edx 986 $test-get-or-insert-handle:first-call: 987 # - start with an empty table, insert one key, verify that it was inserted 988 # copy-array(Heap, "code", h) 989 # . . push args 990 52/push-edx 991 68/push "code"/imm32 992 68/push Heap/imm32 993 # . . call 994 e8/call copy-array/disp32 995 # . . discard args 996 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 997 # eax = get-or-insert-handle(table, h, 12 bytes/row) 998 # . . push args 999 68/push 0xc/imm32/row-size 1000 ff 6/subop/push 1/mod/*+disp8 2/rm32/edx . . . . 4/disp8 . # push *(edx+4) 1001 ff 6/subop/push 0/mod/indirect 2/rm32/edx . . . . . . # push *edx 1002 51/push-ecx 1003 # . . call 1004 e8/call get-or-insert-handle/disp32 1005 # . . discard args 1006 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp 1007 # check-ints-equal(eax - table->data, 8, msg) # first row's value slot returned 1008 # . check-ints-equal(eax - table, 20, msg) 1009 # . . push args 1010 68/push "F - test-get-or-insert-handle/0"/imm32 1011 68/push 0x14/imm32 1012 29/subtract 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . . # subtract ecx from eax 1013 50/push-eax 1014 # . . call 1015 e8/call check-ints-equal/disp32 1016 # . . discard args 1017 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1018 # check-ints-equal(table->write, row-size = 12, msg) 1019 # . . push args 1020 68/push "F - test-get-or-insert-handle/1"/imm32 1021 68/push 0xc/imm32/row-size 1022 ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . . # push *ecx 1023 # . . call 1024 e8/call check-ints-equal/disp32 1025 # . . discard args 1026 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1027 # var curr-addr/eax: (addr array byte) = lookup(table->data) 1028 # . . push args 1029 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 0x10/disp8 . # push *(ecx+16) 1030 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 0xc/disp8 . # push *(ecx+12) 1031 # . . call 1032 e8/call lookup/disp32 1033 # . . discard args 1034 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1035 # check-strings-equal(curr-addr, "code", msg) 1036 # . . push args 1037 68/push "F - test-get-or-insert-handle/2"/imm32 1038 68/push "code"/imm32 1039 50/push-eax 1040 # . . call 1041 e8/call check-strings-equal/disp32 1042 # . . discard args 1043 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1044 $test-get-or-insert-handle:second-call: 1045 # - insert the same key again, verify that it was reused 1046 # copy-array(Heap, "code", h) 1047 # . . push args 1048 52/push-edx 1049 68/push "code"/imm32 1050 68/push Heap/imm32 1051 # . . call 1052 e8/call copy-array/disp32 1053 # . . discard args 1054 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1055 # eax = get-or-insert-handle(table, h, 12 bytes/row) 1056 # . . push args 1057 68/push 0xc/imm32/row-size 1058 ff 6/subop/push 1/mod/*+disp8 2/rm32/edx . . . . 4/disp8 . # push *(edx+4) 1059 ff 6/subop/push 0/mod/indirect 2/rm32/edx . . . . . . # push *edx 1060 51/push-ecx 1061 # . . call 1062 e8/call get-or-insert-handle/disp32 1063 # . . discard args 1064 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp 1065 # check-ints-equal(eax - table->data, 8, msg) 1066 # . check-ints-equal(eax - table, 20, msg) 1067 # . . push args 1068 68/push "F - test-get-or-insert-handle/3"/imm32 1069 68/push 0x14/imm32 1070 29/subtract 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . . # subtract ecx from eax 1071 50/push-eax 1072 # . . call 1073 e8/call check-ints-equal/disp32 1074 # . . discard args 1075 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1076 # no new row inserted 1077 # . check-ints-equal(table->write, row-size = 12, msg) 1078 # . . push args 1079 68/push "F - test-get-or-insert-handle/4"/imm32 1080 68/push 0xc/imm32/row-size 1081 ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . . # push *ecx 1082 # . . call 1083 e8/call check-ints-equal/disp32 1084 # . . discard args 1085 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1086 # curr-addr = lookup(table->data) 1087 # . . push args 1088 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 0x10/disp8 . # push *(ecx+16) 1089 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 0xc/disp8 . # push *(ecx+12) 1090 # . . call 1091 e8/call lookup/disp32 1092 # . . discard args 1093 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1094 # check-strings-equal(curr-addr, "code", msg) 1095 # . . push args 1096 68/push "F - test-get-or-insert-handle/5"/imm32 1097 68/push "code"/imm32 1098 50/push-eax 1099 # . . call 1100 e8/call check-strings-equal/disp32 1101 # . . discard args 1102 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1103 $test-get-or-insert-handle:third-call: 1104 # - insert a new key, verify that it was inserted 1105 # copy-array(Heap, "data", h) 1106 # . . push args 1107 52/push-edx 1108 68/push "data"/imm32 1109 68/push Heap/imm32 1110 # . . call 1111 e8/call copy-array/disp32 1112 # . . discard args 1113 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1114 # eax = get-or-insert-handle(table, h, 12 bytes/row) 1115 # . . push args 1116 68/push 0xc/imm32/row-size 1117 ff 6/subop/push 1/mod/*+disp8 2/rm32/edx . . . . 4/disp8 . # push *(edx+4) 1118 ff 6/subop/push 0/mod/indirect 2/rm32/edx . . . . . . # push *edx 1119 51/push-ecx 1120 # . . call 1121 e8/call get-or-insert-handle/disp32 1122 # . . discard args 1123 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp 1124 # table gets a new row 1125 # check-ints-equal(eax - table->data, 20, msg) # second row's value slot returned 1126 # . check-ints-equal(eax - table, 32, msg) 1127 # . . push args 1128 68/push "F - test-get-or-insert-handle/6"/imm32 1129 68/push 0x20/imm32 1130 29/subtract 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . . # subtract ecx from eax 1131 50/push-eax 1132 # . . call 1133 e8/call check-ints-equal/disp32 1134 # . . discard args 1135 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1136 # check-ints-equal(table->write, 2 rows = 24, msg) 1137 # . . push args 1138 68/push "F - test-get-or-insert-handle/7"/imm32 1139 68/push 0x18/imm32/two-rows 1140 ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . . # push *ecx 1141 # . . call 1142 e8/call check-ints-equal/disp32 1143 # . . discard args 1144 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1145 # curr-addr = lookup(table->data+12) 1146 # . . push args 1147 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 0x1c/disp8 . # push *(ecx+28) 1148 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 0x18/disp8 . # push *(ecx+24) 1149 # . . call 1150 e8/call lookup/disp32 1151 # . . discard args 1152 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1153 # check-strings-equal(curr-addr, "data", msg) 1154 # . . push args 1155 68/push "F - test-get-or-insert-handle/8"/imm32 1156 68/push "data"/imm32 1157 50/push-eax 1158 # . . call 1159 e8/call check-strings-equal/disp32 1160 # . . discard args 1161 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1162 $test-get-or-insert-handle:end: 1163 # . epilogue 1164 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 1165 5d/pop-to-ebp 1166 c3/return 1167 1168 # if no row is found, save 'key' in the next available row 1169 # if there are no rows free, abort 1170 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) 1171 # pseudocode: 1172 # curr = table->data 1173 # max = &table->data[table->write] 1174 # while curr < max 1175 # var c: (addr array byte) = lookup(*curr) 1176 # if slice-equal?(key, *curr) 1177 # return curr+8 1178 # curr += row-size 1179 # if table->write >= table->size 1180 # abort 1181 # zero-out(max, row-size) 1182 # slice-to-string(ad, key, max) 1183 # table->write += row-size 1184 # return max+8 1185 # 1186 # . prologue 1187 55/push-ebp 1188 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 1189 # . save registers 1190 51/push-ecx 1191 52/push-edx 1192 56/push-esi 1193 # esi = table 1194 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 . # copy *(ebp+8) to esi 1195 # var curr/ecx: (addr handle array byte) = table->data 1196 8d/copy-address 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 0xc/disp8 . # copy esi+12 to ecx 1197 # var max/edx: (addr byte) = &table->data[table->write] 1198 8b/copy 0/mod/indirect 6/rm32/esi . . . 2/r32/edx . . # copy *esi to edx 1199 8d/copy-address 0/mod/indirect 4/rm32/sib 1/base/ecx 2/index/edx . 2/r32/edx . . # copy ecx+edx to edx 1200 $get-or-insert-slice:search-loop: 1201 # if (curr >= max) break 1202 39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx 1203 73/jump-if-addr>= $get-or-insert-slice:not-found/disp8 1204 # var c/eax: (addr array byte) = lookup(*curr) 1205 # . . push args 1206 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 4/disp8 . # push *(ecx+4) 1207 ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . . # push *ecx 1208 # . . call 1209 e8/call lookup/disp32 1210 # . . discard args 1211 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1212 # if (slice-equal?(key, c)) return curr+4 1213 # . eax = slice-equal?(key, c) 1214 # . . push args 1215 50/push-eax 1216 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) 1217 # . . call 1218 e8/call slice-equal?/disp32 1219 # . . discard args 1220 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1221 # . if (eax != false) return eax = curr+8 1222 3d/compare-eax-and 0/imm32/false 1223 74/jump-if-= $get-or-insert-slice:mismatch/disp8 1224 8d/copy-address 1/mod/*+disp8 1/rm32/ecx . . . 0/r32/eax 8/disp8 . # copy ecx+8 to eax 1225 eb/jump $get-or-insert-slice:end/disp8 1226 $get-or-insert-slice:mismatch: 1227 # curr += row-size 1228 03/add 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 0x10/disp8 . # add *(ebp+16) to ecx 1229 # loop 1230 eb/jump $get-or-insert-slice:search-loop/disp8 1231 $get-or-insert-slice:not-found: 1232 # result/eax = 0 1233 31/xor 3/mod/direct 0/rm32/eax . . . 0/r32/eax . . # clear eax 1234 # if (table->write >= table->size) abort 1235 8b/copy 0/mod/indirect 6/rm32/esi . . . 1/r32/ecx . . # copy *esi to ecx 1236 3b/compare 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 8/disp8 . # compare ecx with *(esi+8) 1237 7d/jump-if->= $get-or-insert-slice:abort/disp8 1238 # zero-out(max, row-size) 1239 # . . push args 1240 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x10/disp8 . # push *(ebp+16) 1241 52/push-edx 1242 # . . call 1243 e8/call zero-out/disp32 1244 # . . discard args 1245 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1246 # slice-to-string(ad, key, max) 1247 # . . push args 1248 52/push-edx 1249 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) 1250 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x14/disp8 . # push *(ebp+20) 1251 # . . call 1252 e8/call slice-to-string/disp32 1253 # . . discard args 1254 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1255 # table->write += row-size 1256 # . eax = row-size 1257 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 0x10/disp8 . # copy *(ebp+16) to eax 1258 # . table->write += eax 1259 01/add 0/mod/indirect 6/rm32/esi . . . 0/r32/eax . . # add eax to *esi 1260 # return max+8 1261 # . eax = max 1262 89/copy 3/mod/direct 0/rm32/eax . . . 2/r32/edx . . # copy edx to eax 1263 # . eax += 8 1264 05/add-to-eax 8/imm32 1265 $get-or-insert-slice:end: 1266 # . restore registers 1267 5e/pop-to-esi 1268 5a/pop-to-edx 1269 59/pop-to-ecx 1270 # . epilogue 1271 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 1272 5d/pop-to-ebp 1273 c3/return 1274 1275 $get-or-insert-slice:abort: 1276 # . _write(2/stderr, error) 1277 # . . push args 1278 68/push "get-or-insert-slice: table is full\n"/imm32 1279 68/push 2/imm32/stderr 1280 # . . call 1281 e8/call _write/disp32 1282 # . . discard args 1283 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1284 # . syscall_exit(1) 1285 bb/copy-to-ebx 1/imm32 1286 e8/call syscall_exit/disp32 1287 # never gets here 1288 1289 test-get-or-insert-slice: 1290 # . prologue 1291 55/push-ebp 1292 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 1293 # var table/ecx: (stream {string, number} 24) # 2 rows * 12 bytes/row 1294 81 5/subop/subtract 3/mod/direct 4/rm32/esp . . . . . 0x18/imm32 # subtract from esp 1295 68/push 0x18/imm32/size 1296 68/push 0/imm32/read 1297 68/push 0/imm32/write 1298 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 1299 # (eax..edx) = "code" 1300 b8/copy-to-eax "code"/imm32 1301 8b/copy 0/mod/indirect 0/rm32/eax . . . 2/r32/edx . . # copy *eax to edx 1302 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 1303 05/add-to-eax 4/imm32 1304 # var slice/edx: slice = {eax, edx} 1305 52/push-edx 1306 50/push-eax 1307 89/copy 3/mod/direct 2/rm32/edx . . . 4/r32/esp . . # copy esp to edx 1308 $test-get-or-insert-slice:first-call: 1309 # - start with an empty table, insert one key, verify that it was inserted 1310 # eax = get-or-insert-slice(table, "code" slice, 12 bytes/row, Heap) 1311 # . . push args 1312 68/push Heap/imm32 1313 68/push 0xc/imm32/row-size 1314 52/push-edx 1315 51/push-ecx 1316 # . . call 1317 e8/call get-or-insert-slice/disp32 1318 # . . discard args 1319 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp 1320 # check-ints-equal(eax - table->data, 8, msg) # first row's value slot returned 1321 # . check-ints-equal(eax - table, 20, msg) 1322 # . . push args 1323 68/push "F - test-get-or-insert-slice/0"/imm32 1324 68/push 0x14/imm32 1325 29/subtract 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . . # subtract ecx from eax 1326 50/push-eax 1327 # . . call 1328 e8/call check-ints-equal/disp32 1329 # . . discard args 1330 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1331 # check-ints-equal(table->write, row-size = 12, msg) 1332 # . . push args 1333 68/push "F - test-get-or-insert-slice/1"/imm32 1334 68/push 0xc/imm32/row-size 1335 ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . . # push *ecx 1336 # . . call 1337 e8/call check-ints-equal/disp32 1338 # . . discard args 1339 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1340 # var curr-addr/eax: (addr array byte) = lookup(table->data) 1341 # . . push args 1342 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 0x10/disp8 . # push *(ecx+16) 1343 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 0xc/disp8 . # push *(ecx+12) 1344 # . . call 1345 e8/call lookup/disp32 1346 # . . discard args 1347 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1348 # check-strings-equal(curr-addr, "code", msg) 1349 # . . push args 1350 68/push "F - test-get-or-insert-slice/2"/imm32 1351 68/push "code"/imm32 1352 50/push-eax 1353 # . . call 1354 e8/call check-strings-equal/disp32 1355 # . . discard args 1356 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1357 $test-get-or-insert-slice:second-call: 1358 # - insert the same key again, verify that it was reused 1359 # eax = get-or-insert-slice(table, "code" slice, 12 bytes/row) 1360 # . . push args 1361 68/push Heap/imm32 1362 68/push 0xc/imm32/row-size 1363 52/push-edx 1364 51/push-ecx 1365 # . . call 1366 e8/call get-or-insert-slice/disp32 1367 # . . discard args 1368 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp 1369 # check-ints-equal(eax - table->data, 8, msg) 1370 # . check-ints-equal(eax - table, 20, msg) 1371 # . . push args 1372 68/push "F - test-get-or-insert-slice/3"/imm32 1373 68/push 0x14/imm32 1374 29/subtract 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . . # subtract ecx from eax 1375 50/push-eax 1376 # . . call 1377 e8/call check-ints-equal/disp32 1378 # . . discard args 1379 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1380 # no new row inserted 1381 # . check-ints-equal(table->write, row-size = 12, msg) 1382 # . . push args 1383 68/push "F - test-get-or-insert-slice/4"/imm32 1384 68/push 0xc/imm32/row-size 1385 ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . . # push *ecx 1386 # . . call 1387 e8/call check-ints-equal/disp32 1388 # . . discard args 1389 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1390 # curr-addr = lookup(table->data) 1391 # . . push args 1392 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 0x10/disp8 . # push *(ecx+16) 1393 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 0xc/disp8 . # push *(ecx+12) 1394 # . . call 1395 e8/call lookup/disp32 1396 # . . discard args 1397 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1398 # check-strings-equal(curr-addr, "code", msg) 1399 # . . push args 1400 68/push "F - test-get-or-insert-slice/5"/imm32 1401 68/push "code"/imm32 1402 50/push-eax 1403 # . . call 1404 e8/call check-strings-equal/disp32 1405 # . . discard args 1406 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1407 $test-get-or-insert-slice:third-call: 1408 # - insert a new key, verify that it was inserted 1409 # (eax..edx) = "data" 1410 b8/copy-to-eax "data"/imm32 1411 8b/copy 0/mod/indirect 0/rm32/eax . . . 2/r32/edx . . # copy *eax to edx 1412 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 1413 05/add-to-eax 4/imm32 1414 # var slice/edx: slice = {eax, edx} 1415 52/push-edx 1416 50/push-eax 1417 89/copy 3/mod/direct 2/rm32/edx . . . 4/r32/esp . . # copy esp to edx 1418 # eax = get-or-insert-slice(table, "data" slice, 12 bytes/row) 1419 # . . push args 1420 68/push Heap/imm32 1421 68/push 0xc/imm32/row-size 1422 52/push-edx 1423 51/push-ecx 1424 # . . call 1425 e8/call get-or-insert-slice/disp32 1426 # . . discard args 1427 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp 1428 # table gets a new row 1429 # check-ints-equal(eax - table->data, 20, msg) # second row's value slot returned 1430 # . check-ints-equal(eax - table, 32, msg) 1431 # . . push args 1432 68/push "F - test-get-or-insert-slice/6"/imm32 1433 68/push 0x20/imm32 1434 29/subtract 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . . # subtract ecx from eax 1435 50/push-eax 1436 # . . call 1437 e8/call check-ints-equal/disp32 1438 # . . discard args 1439 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1440 # check-ints-equal(table->write, 2 rows = 24, msg) 1441 # . . push args 1442 68/push "F - test-get-or-insert-slice/7"/imm32 1443 68/push 0x18/imm32/two-rows 1444 ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . . # push *ecx 1445 # . . call 1446 e8/call check-ints-equal/disp32 1447 # . . discard args 1448 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1449 # curr-addr = lookup(table->data+12) 1450 # . . push args 1451 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 0x1c/disp8 . # push *(ecx+28) 1452 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 0x18/disp8 . # push *(ecx+24) 1453 # . . call 1454 e8/call lookup/disp32 1455 # . . discard args 1456 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1457 # check-strings-equal(curr-addr, "data", msg) 1458 # . . push args 1459 68/push "F - test-get-or-insert-slice/8"/imm32 1460 68/push "data"/imm32 1461 50/push-eax 1462 # . . call 1463 e8/call check-strings-equal/disp32 1464 # . . discard args 1465 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1466 $test-get-or-insert-slice:end: 1467 # . epilogue 1468 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 1469 5d/pop-to-ebp 1470 c3/return 1471 1472 # if no row is found, save 'key' in the next available row 1473 # if there are no rows free, abort 1474 insert-slice-or-abort: # table: (addr stream {(handle array byte), T}), key: (addr slice), row-size: int, ad: (addr allocation-descriptor) -> result/eax: (addr T) 1475 # pseudocode: 1476 # curr = table->data 1477 # max = &table->data[table->write] 1478 # while curr < max 1479 # var c: (addr array byte) = lookup(*curr) 1480 # if slice-equal?(key, *curr) 1481 # return curr+8 1482 # curr += row-size 1483 # if table->write >= table->size 1484 # abort 1485 # zero-out(max, row-size) 1486 # slice-to-string(ad, key, max) 1487 # table->write += row-size 1488 # return max+8 1489 # 1490 # . prologue 1491 55/push-ebp 1492 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 1493 # . save registers 1494 51/push-ecx 1495 52/push-edx 1496 56/push-esi 1497 # esi = table 1498 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 . # copy *(ebp+8) to esi 1499 # var curr/ecx: (addr handle array byte) = table->data 1500 8d/copy-address 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 0xc/disp8 . # copy esi+12 to ecx 1501 # var max/edx: (addr byte) = &table->data[table->write] 1502 8b/copy 0/mod/indirect 6/rm32/esi . . . 2/r32/edx . . # copy *esi to edx 1503 8d/copy-address 0/mod/indirect 4/rm32/sib 1/base/ecx 2/index/edx . 2/r32/edx . . # copy ecx+edx to edx 1504 $insert-slice-or-abort:search-loop: 1505 # if (curr >= max) break 1506 39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx 1507 73/jump-if-addr>= $insert-slice-or-abort:not-found/disp8 1508 # var c/eax: (addr array byte) = lookup(*curr) 1509 # . . push args 1510 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 4/disp8 . # push *(ecx+4) 1511 ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . . # push *ecx 1512 # . . call 1513 e8/call lookup/disp32 1514 # . . discard args 1515 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1516 # if (slice-equal?(key, c)) abort 1517 # . eax = slice-equal?(key, c) 1518 # . . push args 1519 50/push-eax 1520 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) 1521 # . . call 1522 e8/call slice-equal?/disp32 1523 # . . discard args 1524 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1525 # . if (eax != false) abort 1526 3d/compare-eax-and 0/imm32/false 1527 0f 85/jump-if-!= $insert-slice-or-abort:error-duplicate/disp32 1528 # curr += row-size 1529 03/add 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 0x10/disp8 . # add *(ebp+16) to ecx 1530 # loop 1531 eb/jump $insert-slice-or-abort:search-loop/disp8 1532 $insert-slice-or-abort:not-found: 1533 # result/eax = 0 1534 31/xor 3/mod/direct 0/rm32/eax . . . 0/r32/eax . . # clear eax 1535 # if (table->write >= table->size) abort 1536 8b/copy 0/mod/indirect 6/rm32/esi . . . 1/r32/ecx . . # copy *esi to ecx 1537 3b/compare 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 8/disp8 . # compare ecx with *(esi+8) 1538 0f 8d/jump-if->= $insert-slice-or-abort:error-full/disp32 1539 # zero-out(max, row-size) 1540 # . . push args 1541 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x10/disp8 . # push *(ebp+16) 1542 52/push-edx 1543 # . . call 1544 e8/call zero-out/disp32 1545 # . . discard args 1546 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1547 # slice-to-string(ad, key, max) 1548 # . . push args 1549 52/push-edx 1550 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) 1551 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x14/disp8 . # push *(ebp+20) 1552 # . . call 1553 e8/call slice-to-string/disp32 1554 # . . discard args 1555 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1556 # table->write += row-size 1557 # . eax = row-size 1558 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 0x10/disp8 . # copy *(ebp+16) to eax 1559 # . table->write += eax 1560 01/add 0/mod/indirect 6/rm32/esi . . . 0/r32/eax . . # add eax to *esi 1561 # return max+8 1562 # . eax = max 1563 89/copy 3/mod/direct 0/rm32/eax . . . 2/r32/edx . . # copy edx to eax 1564 # . eax += 8 1565 05/add-to-eax 8/imm32 1566 $insert-slice-or-abort:end: 1567 # . restore registers 1568 5e/pop-to-esi 1569 5a/pop-to-edx 1570 59/pop-to-ecx 1571 # . epilogue 1572 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 1573 5d/pop-to-ebp 1574 c3/return 1575 1576 $insert-slice-or-abort:error-duplicate: 1577 # . flush(Stderr) 1578 # . . push args 1579 68/push Stderr/imm32 1580 # . . call 1581 e8/call flush/disp32 1582 # . . discard args 1583 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1584 # . _write(2/stderr, error) 1585 # . . push args 1586 68/push "insert-slice-or-abort: key already exists: "/imm32 1587 68/push 2/imm32/stderr 1588 # . . call 1589 e8/call _write/disp32 1590 # . . discard args 1591 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1592 # . write-slice-buffered(Stderr, key) 1593 # . . push args 1594 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) 1595 68/push Stderr/imm32 1596 # . . call 1597 e8/call write-slice-buffered/disp32 1598 # . . discard args 1599 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1600 # . flush(Stderr) 1601 # . . push args 1602 68/push Stderr/imm32 1603 # . . call 1604 e8/call flush/disp32 1605 # . . discard args 1606 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1607 # . _write(2/stderr, "\n") 1608 # . . push args 1609 68/push "\n"/imm32 1610 68/push 2/imm32/stderr 1611 # . . call 1612 e8/call _write/disp32 1613 # . . discard args 1614 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1615 # . syscall_exit(1) 1616 bb/copy-to-ebx 1/imm32 1617 e8/call syscall_exit/disp32 1618 # never gets here 1619 1620 $insert-slice-or-abort:error-full: 1621 # . _write(2/stderr, error) 1622 # . . push args 1623 68/push "insert-slice-or-abort: table is full\n"/imm32 1624 68/push 2/imm32/stderr 1625 # . . call 1626 e8/call _write/disp32 1627 # . . discard args 1628 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1629 # . syscall_exit(1) 1630 bb/copy-to-ebx 1/imm32 1631 e8/call syscall_exit/disp32 1632 # never gets here 1633 1634 1635 # if no row is found, stop(ed) 1636 get-or-stop: # table: (addr stream {(handle array byte), T}), key: (addr array byte), row-size: int, 1637 # abort-message-prefix: (addr array byte), err: (addr buffered-file), ed: (addr exit-descriptor) 1638 # -> result/eax: (addr T) 1639 # pseudocode: 1640 # curr = table->data 1641 # max = &table->data[table->write] 1642 # while curr < max 1643 # var c: (addr array byte) = lookup(*curr) 1644 # if string-equal?(key, c) 1645 # return curr+8 1646 # curr += row-size 1647 # write-buffered(err, msg) 1648 # stop(ed) 1649 # 1650 # . prologue 1651 55/push-ebp 1652 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 1653 # . save registers 1654 51/push-ecx 1655 52/push-edx 1656 56/push-esi 1657 # esi = table 1658 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 . # copy *(ebp+8) to esi 1659 # var curr/ecx: (addr handle array byte) = table->data 1660 8d/copy-address 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 0xc/disp8 . # copy esi+12 to ecx 1661 # var max/edx: (addr byte) = &table->data[table->write] 1662 8b/copy 0/mod/indirect 6/rm32/esi . . . 2/r32/edx . . # copy *esi to edx 1663 8d/copy-address 0/mod/indirect 4/rm32/sib 1/base/ecx 2/index/edx . 2/r32/edx . . # copy ecx+edx to edx 1664 $get-or-stop:search-loop: 1665 # if (curr >= max) stop(ed) 1666 39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx 1667 73/jump-if-addr>= $get-or-stop:stop/disp8 1668 # var c/eax: (addr array byte) = lookup(*curr) 1669 # . . push args 1670 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 4/disp8 . # push *(ecx+4) 1671 ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . . # push *ecx 1672 # . . call 1673 e8/call lookup/disp32 1674 # . . discard args 1675 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1676 # if (string-equal?(key, c)) return curr+8 1677 # . eax = string-equal?(key, c) 1678 # . . push args 1679 50/push-eax 1680 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) 1681 # . . call 1682 e8/call string-equal?/disp32 1683 # . . discard args 1684 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1685 # . if (eax != false) return eax = curr+8 1686 3d/compare-eax-and 0/imm32/false 1687 74/jump-if-= $get-or-stop:mismatch/disp8 1688 8d/copy-address 1/mod/*+disp8 1/rm32/ecx . . . 0/r32/eax 8/disp8 . # copy ecx+8 to eax 1689 eb/jump $get-or-stop:end/disp8 1690 $get-or-stop:mismatch: 1691 # curr += row-size 1692 03/add 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 0x10/disp8 . # add *(ebp+16) to ecx 1693 # loop 1694 eb/jump $get-or-stop:search-loop/disp8 1695 $get-or-stop:end: 1696 # . restore registers 1697 5e/pop-to-esi 1698 5a/pop-to-edx 1699 59/pop-to-ecx 1700 # . epilogue 1701 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 1702 5d/pop-to-ebp 1703 c3/return 1704 1705 $get-or-stop:stop: 1706 # . write-buffered(err, abort-message-prefix) 1707 # . . push args 1708 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x14/disp8 . # push *(ebp+20) 1709 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x18/disp8 . # push *(ebp+24) 1710 # . . call 1711 e8/call write-buffered/disp32 1712 # . . discard args 1713 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1714 # . write-buffered(err, error) 1715 # . . push args 1716 68/push ": get-or-stop: key not found: "/imm32 1717 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x18/disp8 . # push *(ebp+24) 1718 # . . call 1719 e8/call write-buffered/disp32 1720 # . . discard args 1721 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1722 # . write-buffered(err, key) 1723 # . . push args 1724 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) 1725 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x18/disp8 . # push *(ebp+24) 1726 # . . call 1727 e8/call write-buffered/disp32 1728 # . . discard args 1729 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1730 # . write-buffered(err, "\n") 1731 # . . push args 1732 68/push Newline/imm32 1733 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x18/disp8 . # push *(ebp+24) 1734 # . . call 1735 e8/call write-buffered/disp32 1736 # . . discard args 1737 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1738 # . stop(ed, 1) 1739 # . . push args 1740 68/push 1/imm32 1741 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x1c/disp8 . # push *(ebp+28) 1742 # . . call 1743 e8/call stop/disp32 1744 # never gets here 1745 $get-or-stop:terminus: 1746 # . . discard args 1747 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1748 # syscall_exit(1) 1749 bb/copy-to-ebx 1/imm32 1750 e8/call syscall_exit/disp32 1751 1752 test-get-or-stop: 1753 # This test uses exit-descriptors. Use ebp for setting up local variables. 1754 # . prologue 1755 55/push-ebp 1756 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 1757 # setup 1758 # . clear-stream(_test-error-stream) 1759 # . . push args 1760 68/push _test-error-stream/imm32 1761 # . . call 1762 e8/call clear-stream/disp32 1763 # . . discard args 1764 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1765 # . clear-stream($_test-error-buffered-file->buffer) 1766 # . . push args 1767 68/push $_test-error-buffered-file->buffer/imm32 1768 # . . call 1769 e8/call clear-stream/disp32 1770 # . . discard args 1771 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1772 # var table/ecx: (stream {string, number} 24) # 2 rows * 12 bytes/row 1773 81 5/subop/subtract 3/mod/direct 4/rm32/esp . . . . . 0x18/imm32 # subtract from esp 1774 68/push 0x18/imm32/size 1775 68/push 0/imm32/read 1776 68/push 0/imm32/write 1777 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 1778 # var ed/edx: exit-descriptor 1779 68/push 0/imm32 1780 68/push 0/imm32 1781 89/copy 3/mod/direct 2/rm32/edx . . . 4/r32/esp . . # copy esp to edx 1782 # size 'ed' for the calls to 'get-or-stop' 1783 # . tailor-exit-descriptor(ed, 24) 1784 # . . push args 1785 68/push 0x18/imm32/nbytes-of-args-for-get-or-stop 1786 52/push-edx 1787 # . . call 1788 e8/call tailor-exit-descriptor/disp32 1789 # . . discard args 1790 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1791 # insert(table, "code", 12 bytes/row, Heap) 1792 # . . push args 1793 68/push Heap/imm32 1794 68/push 0xc/imm32/row-size 1795 68/push "code"/imm32 1796 51/push-ecx 1797 # . . call 1798 e8/call get-or-insert/disp32 1799 # . . discard args 1800 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp 1801 $test-get-or-stop:success: 1802 # eax = get-or-stop(table, "code", row-size=12, msg, _test-error-buffered-file, ed) 1803 # . . push args 1804 52/push-edx/ed 1805 68/push _test-error-buffered-file/imm32 1806 68/push "foo"/imm32/abort-prefix 1807 68/push 0xc/imm32/row-size 1808 68/push "code"/imm32 1809 51/push-ecx 1810 # . . call 1811 e8/call get-or-stop/disp32 1812 # . . discard args 1813 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x18/imm32 # add to esp 1814 $test-get-or-stop:success-assertion: 1815 # check-ints-equal(eax - table->data, 8, msg) 1816 # . check-ints-equal(eax - table, 20, msg) 1817 # . . push args 1818 68/push "F - test-get-or-stop/0"/imm32 1819 68/push 0x14/imm32 1820 29/subtract 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . . # subtract ecx from eax 1821 50/push-eax 1822 # . . call 1823 e8/call check-ints-equal/disp32 1824 # . . discard args 1825 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1826 $test-get-or-stop:failure: 1827 # eax = get-or-stop(table, "data", row-size=12, msg, _test-error-buffered-file, ed) 1828 # . . push args 1829 52/push-edx/ed 1830 68/push _test-error-buffered-file/imm32 1831 68/push "foo"/imm32/abort-prefix 1832 68/push 0xc/imm32/row-size 1833 68/push "data"/imm32 1834 51/push-ecx 1835 # . . call 1836 e8/call get-or-stop/disp32 1837 # registers except esp may be clobbered at this point 1838 # restore register args, discard others 1839 59/pop-to-ecx 1840 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp 1841 5a/pop-to-edx 1842 $test-get-or-stop:failure-assertion: 1843 # check that get-or-stop tried to call stop(1) 1844 # . check-ints-equal(ed->value, 2, msg) 1845 # . . push args 1846 68/push "F - test-get-or-stop/1"/imm32 1847 68/push 2/imm32 1848 # . . push ed->value 1849 ff 6/subop/push 1/mod/*+disp8 2/rm32/edx . . . . 4/disp8 . # push *(edx+4) 1850 # . . call 1851 e8/call check-ints-equal/disp32 1852 # . . discard args 1853 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1854 $test-get-or-stop:end: 1855 # . epilogue 1856 # don't restore esp from ebp; manually reclaim locals 1857 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x2c/imm32 # add to esp 1858 5d/pop-to-ebp 1859 c3/return 1860 1861 # if no row is found, stop(ed) 1862 get-slice-or-stop: # table: (addr stream {(handle array byte), _}), key: (addr slice), row-size: int, 1863 # abort-message-prefix: (addr string), err: (addr buffered-file), ed: (addr exit-descriptor) 1864 # -> result/eax: (addr _) 1865 # pseudocode: 1866 # curr = table->data 1867 # max = &table->data[table->write] 1868 # while curr < max 1869 # var c: (addr array byte) = lookup(*curr) 1870 # if slice-equal?(key, c) 1871 # return curr+8 1872 # curr += row-size 1873 # write-buffered(err, msg) 1874 # stop(ed) 1875 # 1876 # . prologue 1877 55/push-ebp 1878 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 1879 # . save registers 1880 51/push-ecx 1881 52/push-edx 1882 56/push-esi 1883 # esi = table 1884 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 . # copy *(ebp+8) to esi 1885 # var curr/ecx: (addr handle array byte) = table->data 1886 8d/copy-address 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 0xc/disp8 . # copy esi+12 to ecx 1887 # var max/edx: (addr byte) = &table->data[table->write] 1888 8b/copy 0/mod/indirect 6/rm32/esi . . . 2/r32/edx . . # copy *esi to edx 1889 8d/copy-address 0/mod/indirect 4/rm32/sib 1/base/ecx 2/index/edx . 2/r32/edx . . # copy ecx+edx to edx 1890 $get-slice-or-stop:search-loop: 1891 # if (curr >= max) stop(ed) 1892 39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx 1893 73/jump-if-addr>= $get-slice-or-stop:stop/disp8 1894 # var c/eax: (addr array byte) = lookup(*curr) 1895 # . . push args 1896 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 4/disp8 . # push *(ecx+4) 1897 ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . . # push *ecx 1898 # . . call 1899 e8/call lookup/disp32 1900 # . . discard args 1901 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1902 # if (slice-equal?(key, c)) return curr+4 1903 # . eax = slice-equal?(key, c) 1904 # . . push args 1905 50/push-eax 1906 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) 1907 # . . call 1908 e8/call slice-equal?/disp32 1909 # . . discard args 1910 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1911 # . if (eax != false) return eax = curr+8 1912 3d/compare-eax-and 0/imm32/false 1913 74/jump-if-= $get-slice-or-stop:mismatch/disp8 1914 8d/copy-address 1/mod/*+disp8 1/rm32/ecx . . . 0/r32/eax 8/disp8 . # copy ecx+8 to eax 1915 eb/jump $get-slice-or-stop:end/disp8 1916 $get-slice-or-stop:mismatch: 1917 # curr += row-size 1918 03/add 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 0x10/disp8 . # add *(ebp+16) to ecx 1919 # loop 1920 eb/jump $get-slice-or-stop:search-loop/disp8 1921 $get-slice-or-stop:end: 1922 # . restore registers 1923 5e/pop-to-esi 1924 5a/pop-to-edx 1925 59/pop-to-ecx 1926 # . epilogue 1927 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 1928 5d/pop-to-ebp 1929 c3/return 1930 1931 $get-slice-or-stop:stop: 1932 # . write-buffered(err, abort-message-prefix) 1933 # . . push args 1934 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x14/disp8 . # push *(ebp+20) 1935 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x18/disp8 . # push *(ebp+24) 1936 # . . call 1937 e8/call write-buffered/disp32 1938 # . . discard args 1939 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1940 # . write-buffered(err, error) 1941 # . . push args 1942 68/push ": get-slice-or-stop: key not found: "/imm32 1943 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x18/disp8 . # push *(ebp+24) 1944 # . . call 1945 e8/call write-buffered/disp32 1946 # . . discard args 1947 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1948 # . write-slice-buffered(err, key) 1949 # . . push args 1950 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) 1951 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x18/disp8 . # push *(ebp+24) 1952 # . . call 1953 e8/call write-slice-buffered/disp32 1954 # . . discard args 1955 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1956 # . write-buffered(err, "\n") 1957 # . . push args 1958 68/push Newline/imm32 1959 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x18/disp8 . # push *(ebp+24) 1960 # . . call 1961 e8/call write-buffered/disp32 1962 # . . discard args 1963 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1964 # . stop(ed, 1) 1965 # . . push args 1966 68/push 1/imm32 1967 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x1c/disp8 . # push *(ebp+28) 1968 # . . call 1969 e8/call stop/disp32 1970 # never gets here 1971 $get-slice-or-stop:terminus: 1972 # . . discard args 1973 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1974 # syscall_exit(1) 1975 bb/copy-to-ebx 1/imm32 1976 e8/call syscall_exit/disp32 1977 1978 test-get-slice-or-stop: 1979 # This test uses exit-descriptors. Use ebp for setting up local variables. 1980 # . prologue 1981 55/push-ebp 1982 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 1983 # setup 1984 # . clear-stream(_test-error-stream) 1985 # . . push args 1986 68/push _test-error-stream/imm32 1987 # . . call 1988 e8/call clear-stream/disp32 1989 # . . discard args 1990 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1991 # . clear-stream($_test-error-buffered-file->buffer) 1992 # . . push args 1993 68/push $_test-error-buffered-file->buffer/imm32 1994 # . . call 1995 e8/call clear-stream/disp32 1996 # . . discard args 1997 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1998 # var table/ecx: (stream {string, number} 24) # 2 rows * 12 bytes/row 1999 81 5/subop/subtract 3/mod/direct 4/rm32/esp . . . . . 0x18/imm32 # subtract from esp 2000 68/push 0x18/imm32/size 2001 68/push 0/imm32/read 2002 68/push 0/imm32/write 2003 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 2004 # var ed/edx: exit-descriptor 2005 68/push 0/imm32 2006 68/push 0/imm32 2007 89/copy 3/mod/direct 2/rm32/edx . . . 4/r32/esp . . # copy esp to edx 2008 # var slice/ebx: slice = "code" 2009 # . (eax..ebx) = "code" 2010 b8/copy-to-eax "code"/imm32 2011 8b/copy 0/mod/indirect 0/rm32/eax . . . 3/r32/ebx . . # copy *eax to ebx 2012 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 2013 05/add-to-eax 4/imm32 2014 # . ebx = {eax, ebx} 2015 53/push-ebx 2016 50/push-eax 2017 89/copy 3/mod/direct 3/rm32/ebx . . . 4/r32/esp . . # copy esp to ebx 2018 # size 'ed' for the calls to 'get-or-stop' (define no locals past this point) 2019 # . tailor-exit-descriptor(ed, 24) 2020 # . . push args 2021 68/push 0x18/imm32/nbytes-of-args-for-get-or-stop 2022 52/push-edx 2023 # . . call 2024 e8/call tailor-exit-descriptor/disp32 2025 # . . discard args 2026 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 2027 # insert(table, "code", 12 bytes/row, Heap) 2028 # . . push args 2029 68/push Heap/imm32 2030 68/push 0xc/imm32/row-size 2031 68/push "code"/imm32 2032 51/push-ecx 2033 # . . call 2034 e8/call get-or-insert/disp32 2035 # . . discard args 2036 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp 2037 $test-get-slice-or-stop:success: 2038 # eax = get-slice-or-stop(table, slice, row-size=12, msg, _test-error-buffered-file, ed) 2039 # . . push args 2040 52/push-edx/ed 2041 68/push _test-error-buffered-file/imm32 2042 68/push "foo"/imm32/abort-prefix 2043 68/push 0xc/imm32/row-size 2044 53/push-ebx/slice 2045 51/push-ecx 2046 # . . call 2047 e8/call get-slice-or-stop/disp32 2048 # registers except esp may be clobbered at this point 2049 # restore register args, discard others 2050 59/pop-to-ecx 2051 5b/pop-to-ebx 2052 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 2053 5a/pop-to-edx 2054 $test-get-slice-or-stop:success-assertion: 2055 # check-ints-equal(eax - table->data, 8, msg) # first row's value slot returned 2056 # . check-ints-equal(eax - table, 20, msg) 2057 # . . push args 2058 68/push "F - test-get-slice-or-stop/0"/imm32 2059 68/push 0x14/imm32 2060 29/subtract 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . . # subtract ecx from eax 2061 50/push-eax 2062 # . . call 2063 e8/call check-ints-equal/disp32 2064 # . . discard args 2065 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 2066 $test-get-slice-or-stop:failure: 2067 # slice = "segment2" 2068 # . *ebx = "segment2"->data 2069 b8/copy-to-eax "segment2"/imm32 2070 05/add-to-eax 4/imm32 2071 89/copy 0/mod/indirect 3/rm32/ebx . . . 0/r32/eax . . # copy eax to *ebx 2072 # . *(ebx+4) = "segment2"->data + len("segment2") 2073 05/add-to-eax 8/imm32/strlen 2074 89/copy 1/mod/*+disp8 3/rm32/ebx . . . 0/r32/eax 4/disp8 . # copy eax to *(ebx+4) 2075 # eax = get-slice-or-stop(table, slice, row-size=12, msg, _test-error-buffered-file, ed) 2076 # . . push args 2077 52/push-edx/ed 2078 68/push _test-error-buffered-file/imm32 2079 68/push "foo"/imm32/abort-prefix 2080 68/push 0xc/imm32/row-size 2081 53/push-ebx/slice 2082 51/push-ecx 2083 # . . call 2084 e8/call get-slice-or-stop/disp32 2085 # registers except esp may be clobbered at this point 2086 # restore register args, discard others 2087 59/pop-to-ecx 2088 5b/pop-to-ebx 2089 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 2090 5a/pop-to-edx 2091 $test-get-slice-or-stop:failure-assertion: 2092 # check that get-or-stop tried to call stop(1) 2093 # . check-ints-equal(ed->value, 2, msg) 2094 # . . push args 2095 68/push "F - test-get-or-stop/1"/imm32 2096 68/push 2/imm32 2097 # . . push ed->value 2098 ff 6/subop/push 1/mod/*+disp8 2/rm32/edx . . . . 4/disp8 . # push *(edx+4) 2099 # . . call 2100 e8/call check-ints-equal/disp32 2101 # . . discard args 2102 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 2103 $test-get-slice-or-stop:end: 2104 # . epilogue 2105 # don't restore esp from ebp; manually reclaim locals 2106 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x34/imm32 # add to esp 2107 5d/pop-to-ebp 2108 c3/return 2109 2110 # if no row is found, return null (0) 2111 maybe-get: # table: (addr stream {(handle array byte), T}), key: (addr array byte), row-size: int -> result/eax: (addr T) 2112 # pseudocode: 2113 # curr = table->data 2114 # max = &table->data[table->write] 2115 # while curr < max 2116 # var c: (addr array byte) = lookup(*curr) 2117 # if string-equal?(key, c) 2118 # return curr+8 2119 # curr += row-size 2120 # return 0 2121 # 2122 # . prologue 2123 55/push-ebp 2124 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 2125 # . save registers 2126 51/push-ecx 2127 52/push-edx 2128 56/push-esi 2129 # esi = table 2130 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 . # copy *(ebp+8) to esi 2131 # var curr/ecx: (addr handle array byte) = table->data 2132 8d/copy-address 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 0xc/disp8 . # copy esi+12 to ecx 2133 # var max/edx: (addr byte) = &table->data[table->write] 2134 8b/copy 0/mod/indirect 6/rm32/esi . . . 2/r32/edx . . # copy *esi to edx 2135 8d/copy-address 0/mod/indirect 4/rm32/sib 1/base/ecx 2/index/edx . 2/r32/edx . . # copy ecx+edx to edx 2136 $maybe-get:search-loop: 2137 # if (curr >= max) return null 2138 39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx 2139 73/jump-if-addr>= $maybe-get:null/disp8 2140 # var c/eax: (addr array byte) = lookup(*curr) 2141 # . . push args 2142 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 4/disp8 . # push *(ecx+4) 2143 ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . . # push *ecx 2144 # . . call 2145 e8/call lookup/disp32 2146 # . . discard args 2147 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 2148 # if (string-equal?(key, c)) return curr+4 2149 # . eax = string-equal?(key, c) 2150 # . . push args 2151 50/push-eax 2152 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) 2153 # . . call 2154 e8/call string-equal?/disp32 2155 # . . discard args 2156 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 2157 # . if (eax != false) return eax = curr+8 2158 3d/compare-eax-and 0/imm32/false 2159 74/jump-if-= $maybe-get:mismatch/disp8 2160 8d/copy-address 1/mod/*+disp8 1/rm32/ecx . . . 0/r32/eax 8/disp8 . # copy ecx+8 to eax 2161 eb/jump $maybe-get:end/disp8 2162 $maybe-get:mismatch: 2163 # curr += row-size 2164 03/add 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 0x10/disp8 . # add *(ebp+16) to ecx 2165 # loop 2166 eb/jump $maybe-get:search-loop/disp8 2167 $maybe-get:null: 2168 b8/copy-to-eax 0/imm32 2169 $maybe-get:end: 2170 # . restore registers 2171 5e/pop-to-esi 2172 5a/pop-to-edx 2173 59/pop-to-ecx 2174 # . epilogue 2175 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 2176 5d/pop-to-ebp 2177 c3/return 2178 2179 test-maybe-get: 2180 # . prologue 2181 55/push-ebp 2182 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 2183 # - setup: create a table with one row 2184 # var table/ecx: (stream {string, number} 24) # 2 rows * 12 bytes/row 2185 81 5/subop/subtract 3/mod/direct 4/rm32/esp . . . . . 0x18/imm32 # subtract from esp 2186 68/push 0x18/imm32/size 2187 68/push 0/imm32/read 2188 68/push 0/imm32/write 2189 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 2190 # eax = get-or-insert(table, "code", 12 bytes/row, Heap) 2191 # . . push args 2192 68/push Heap/imm32 2193 68/push 0xc/imm32/row-size 2194 68/push "code"/imm32 2195 51/push-ecx 2196 # . . call 2197 e8/call get-or-insert/disp32 2198 # . . discard args 2199 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp 2200 $test-maybe-get:success: 2201 # - check for the same key, verify that it was reused 2202 # eax = maybe-get(table, "code", 12 bytes/row) 2203 # . . push args 2204 68/push 0xc/imm32/row-size 2205 68/push "code"/imm32 2206 51/push-ecx 2207 # . . call 2208 e8/call maybe-get/disp32 2209 # . . discard args 2210 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 2211 # check-ints-equal(eax - table->data, 8, msg) 2212 # . check-ints-equal(eax - table, 20, msg) 2213 # . . push args 2214 68/push "F - test-maybe-get/0"/imm32 2215 68/push 0x14/imm32 2216 29/subtract 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . . # subtract ecx from eax 2217 50/push-eax 2218 # . . call 2219 e8/call check-ints-equal/disp32 2220 # . . discard args 2221 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 2222 # no new row inserted 2223 # . check-ints-equal(table->write, row-size = 12, msg) 2224 # . . push args 2225 68/push "F - test-maybe-get/1"/imm32 2226 68/push 0xc/imm32/row-size 2227 ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . . # push *ecx 2228 # . . call 2229 e8/call check-ints-equal/disp32 2230 # . . discard args 2231 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 2232 # var curr-addr/eax: (addr array byte) = lookup(table->data) 2233 # . . push args 2234 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 0x10/disp8 . # push *(ecx+16) 2235 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 0xc/disp8 . # push *(ecx+12) 2236 # . . call 2237 e8/call lookup/disp32 2238 # . . discard args 2239 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 2240 # check-strings-equal(curr-addr, "code", msg) 2241 # . . push args 2242 68/push "F - test-maybe-get/2"/imm32 2243 68/push "code"/imm32 2244 50/push-eax 2245 # . . call 2246 e8/call check-strings-equal/disp32 2247 # . . discard args 2248 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 2249 $test-maybe-get:failure: 2250 # - search for a new key 2251 # eax = maybe-get(table, "data", 12 bytes/row) 2252 # . . push args 2253 68/push 0xc/imm32/row-size 2254 68/push "data"/imm32 2255 51/push-ecx 2256 # . . call 2257 e8/call maybe-get/disp32 2258 # . . discard args 2259 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 2260 # check-ints-equal(eax, 0, msg) 2261 # . . push args 2262 68/push "F - test-maybe-get/3"/imm32 2263 68/push 0/imm32 2264 50/push-eax 2265 # . . call 2266 e8/call check-ints-equal/disp32 2267 # . . discard args 2268 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 2269 $test-maybe-get:end: 2270 # . epilogue 2271 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 2272 5d/pop-to-ebp 2273 c3/return 2274 2275 # if no row is found, return null (0) 2276 maybe-get-slice: # table: (addr stream {(handle array byte), T}), key: (addr slice), row-size: int -> result/eax: (addr T) 2277 # pseudocode: 2278 # curr = table->data 2279 # max = &table->data[table->write] 2280 # while curr < max 2281 # var c: (addr array byte) = lookup(*curr) 2282 # if slice-equal?(key, c) 2283 # return curr+8 2284 # curr += row-size 2285 # return 0 2286 # 2287 # . prologue 2288 55/push-ebp 2289 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 2290 # . save registers 2291 51/push-ecx 2292 52/push-edx 2293 56/push-esi 2294 # esi = table 2295 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 . # copy *(ebp+8) to esi 2296 # var curr/ecx: (addr handle array byte) = table->data 2297 8d/copy-address 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 0xc/disp8 . # copy esi+12 to ecx 2298 # var max/edx: (addr byte) = &table->data[table->write] 2299 8b/copy 0/mod/indirect 6/rm32/esi . . . 2/r32/edx . . # copy *esi to edx 2300 8d/copy-address 0/mod/indirect 4/rm32/sib 1/base/ecx 2/index/edx . 2/r32/edx . . # copy ecx+edx to edx 2301 $maybe-get-slice:search-loop: 2302 # if (curr >= max) return null 2303 39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx 2304 73/jump-if-addr>= $maybe-get-slice:null/disp8 2305 # var c/eax: (addr array byte) = lookup(*curr) 2306 # . . push args 2307 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 4/disp8 . # push *(ecx+4) 2308 ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . . # push *ecx 2309 # . . call 2310 e8/call lookup/disp32 2311 # . . discard args 2312 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 2313 # if (slice-equal?(key, c)) return curr+4 2314 # . eax = slice-equal?(key, c) 2315 # . . push args 2316 50/push-eax 2317 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) 2318 # . . call 2319 e8/call slice-equal?/disp32 2320 # . . discard args 2321 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 2322 # . if (eax != false) return eax = curr+8 2323 3d/compare-eax-and 0/imm32/false 2324 74/jump-if-= $maybe-get-slice:mismatch/disp8 2325 8d/copy-address 1/mod/*+disp8 1/rm32/ecx . . . 0/r32/eax 8/disp8 . # copy ecx+8 to eax 2326 eb/jump $maybe-get-slice:end/disp8 2327 $maybe-get-slice:mismatch: 2328 # curr += row-size 2329 03/add 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 0x10/disp8 . # add *(ebp+16) to ecx 2330 # loop 2331 eb/jump $maybe-get-slice:search-loop/disp8 2332 $maybe-get-slice:null: 2333 b8/copy-to-eax 0/imm32 2334 $maybe-get-slice:end: 2335 # . restore registers 2336 5e/pop-to-esi 2337 5a/pop-to-edx 2338 59/pop-to-ecx 2339 # . epilogue 2340 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 2341 5d/pop-to-ebp 2342 c3/return 2343 2344 test-maybe-get-slice: 2345 # . prologue 2346 55/push-ebp 2347 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 2348 # - setup: create a table with one row 2349 # var table/ecx: (stream {string, number} 24) # 2 rows * 12 bytes/row 2350 81 5/subop/subtract 3/mod/direct 4/rm32/esp . . . . . 0x18/imm32 # subtract from esp 2351 68/push 0x18/imm32/size 2352 68/push 0/imm32/read 2353 68/push 0/imm32/write 2354 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 2355 # insert(table, "code", 12 bytes/row, Heap) 2356 # . . push args 2357 68/push Heap/imm32 2358 68/push 0xc/imm32/row-size 2359 68/push "code"/imm32 2360 51/push-ecx 2361 # . . call 2362 e8/call get-or-insert/disp32 2363 # . . discard args 2364 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp 2365 $test-maybe-get-slice:success: 2366 # - check for the same key, verify that it was reused 2367 # (eax..edx) = "code" 2368 b8/copy-to-eax "code"/imm32 2369 8b/copy 0/mod/indirect 0/rm32/eax . . . 2/r32/edx . . # copy *eax to edx 2370 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 2371 05/add-to-eax 4/imm32 2372 # var slice/edx: slice = {eax, edx} 2373 52/push-edx 2374 50/push-eax 2375 89/copy 3/mod/direct 2/rm32/edx . . . 4/r32/esp . . # copy esp to edx 2376 # eax = maybe-get-slice(table, "code" slice, 12 bytes/row) 2377 # . . push args 2378 68/push 0xc/imm32/row-size 2379 52/push-edx 2380 51/push-ecx 2381 # . . call 2382 e8/call maybe-get-slice/disp32 2383 # . . discard args 2384 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 2385 # check-ints-equal(eax - table->data, 8, msg) 2386 # . check-ints-equal(eax - table, 20, msg) 2387 # . . push args 2388 68/push "F - test-maybe-get-slice/0"/imm32 2389 68/push 0x14/imm32 2390 29/subtract 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . . # subtract ecx from eax 2391 50/push-eax 2392 # . . call 2393 e8/call check-ints-equal/disp32 2394 # . . discard args 2395 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 2396 # no new row inserted 2397 # . check-ints-equal(table->write, row-size = 12, msg) 2398 # . . push args 2399 68/push "F - test-maybe-get-slice/1"/imm32 2400 68/push 0xc/imm32/row-size 2401 ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . . # push *ecx 2402 # . . call 2403 e8/call check-ints-equal/disp32 2404 # . . discard args 2405 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 2406 # var curr-addr/eax: (addr array byte) = lookup(table->data) 2407 # . . push args 2408 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 0x10/disp8 . # push *(ecx+16) 2409 ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 0xc/disp8 . # push *(ecx+12) 2410 # . . call 2411 e8/call lookup/disp32 2412 # . . discard args 2413 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 2414 # check-strings-equal(curr-addr, "code", msg) 2415 # . . push args 2416 68/push "F - test-maybe-get-slice/2"/imm32 2417 68/push "code"/imm32 2418 50/push-eax 2419 # . . call 2420 e8/call check-strings-equal/disp32 2421 # . . discard args 2422 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 2423 $test-maybe-get-slice:failure: 2424 # - search for a new key 2425 # (eax..edx) = "data" 2426 b8/copy-to-eax "data"/imm32 2427 8b/copy 0/mod/indirect 0/rm32/eax . . . 2/r32/edx . . # copy *eax to edx 2428 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 2429 05/add-to-eax 4/imm32 2430 # var slice/edx: slice = {eax, edx} 2431 52/push-edx 2432 50/push-eax 2433 89/copy 3/mod/direct 2/rm32/edx . . . 4/r32/esp . . # copy esp to edx 2434 # eax = maybe-get-slice(table, "data" slice, 12 bytes/row) 2435 # . . push args 2436 68/push 0xc/imm32/row-size 2437 52/push-edx 2438 51/push-ecx 2439 # . . call 2440 e8/call maybe-get-slice/disp32 2441 # . . discard args 2442 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 2443 # check-ints-equal(eax, 0, msg) 2444 # . . push args 2445 68/push "F - test-maybe-get-slice/3"/imm32 2446 68/push 0/imm32 2447 50/push-eax 2448 # . . call 2449 e8/call check-ints-equal/disp32 2450 # . . discard args 2451 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 2452 $test-maybe-get-slice:end: 2453 # . epilogue 2454 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 2455 5d/pop-to-ebp 2456 c3/return 2457 2458 # . . vim:nowrap:textwidth=0