https://github.com/akkartik/mu/blob/master/subx/072slice.subx
  1 # new data structure: a slice is an open interval of addresses [start, end)
  2 # that includes 'start' but not 'end'
  3 
  4 == code
  5 #   instruction                     effective address                                                   register    displacement    immediate
  6 # . op          subop               mod             rm32          base        index         scale       r32
  7 # . 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
  8 
  9 #? Entry:  # run a single test, while debugging
 10 #?     e8/call test-slice-to-string/disp32
 11 #?     # syscall(exit, Num-test-failures)
 12 #?     8b/copy                         0/mod/indirect  5/rm32/.disp32            .             .           3/r32/EBX   Num-test-failures/disp32          # copy *Num-test-failures to EBX
 13 #?     b8/copy-to-EAX  1/imm32/exit
 14 #?     cd/syscall  0x80/imm8
 15 
 16 slice-empty?:  # s : (address slice) -> EAX : boolean
 17     # . prolog
 18     55/push-EBP
 19     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
 20     # . save registers
 21     51/push-ECX
 22     # ECX = s
 23     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           1/r32/ECX   8/disp8         .                 # copy *(EBP+8) to ECX
 24     # if (s->start == s->end) return true
 25     # . EAX = s->start
 26     8b/copy                         0/mod/indirect  1/rm32/ECX    .           .             .           0/r32/EAX   .               .                 # copy *ECX to EAX
 27     # . compare EAX and s->end
 28     39/compare                      1/mod/*+disp8   1/rm32/ECX    .           .             .           0/r32/EAX   4/disp8         .                 # compare EAX and *(ECX+4)
 29     b8/copy-to-EAX  1/imm32/true
 30     74/jump-if-equal  $slice-empty?:end/disp8
 31     b8/copy-to-EAX  0/imm32/false
 32 $slice-empty?:end:
 33     # . restore registers
 34     59/pop-to-ECX
 35     # . epilog
 36     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
 37     5d/pop-to-EBP
 38     c3/return
 39 
 40 test-slice-empty-true:
 41     # . prolog
 42     55/push-EBP
 43     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
 44     # var slice/ECX = {34, 34}
 45     68/push  34/imm32/end
 46     68/push  34/imm32/start
 47     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
 48     # slice-empty?(slice)
 49     # . . push args
 50     51/push-ECX
 51     # . . call
 52     e8/call  slice-empty?/disp32
 53     # . . discard args
 54     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
 55     # check-ints-equal(EAX, 1, msg)
 56     # . . push args
 57     68/push  "F - test-slice-empty-true"/imm32
 58     68/push  1/imm32
 59     50/push-EAX
 60     # . . call
 61     e8/call  check-ints-equal/disp32
 62     # . . discard args
 63     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
 64     # . epilog
 65     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
 66     5d/pop-to-EBP
 67     c3/return
 68 
 69 test-slice-empty-false:
 70     # . prolog
 71     55/push-EBP
 72     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
 73     # var slice/ECX = {34, 23}
 74     68/push  23/imm32/end
 75     68/push  34/imm32/start
 76     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
 77     # slice-empty?(slice)
 78     # . . push args
 79     51/push-ECX
 80     # . . call
 81     e8/call  slice-empty?/disp32
 82     # . . discard args
 83     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
 84     # check-ints-equal(EAX, 0, msg)
 85     # . . push args
 86     68/push  "F - test-slice-empty-false"/imm32
 87     68/push  0/imm32
 88     50/push-EAX
 89     # . . call
 90     e8/call  check-ints-equal/disp32
 91     # . . discard args
 92     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
 93     # . epilog
 94     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
 95     5d/pop-to-EBP
 96     c3/return
 97 
 98 slice-equal?:  # s : (address slice), p : (address string) -> EAX : boolean
 99     # pseudocode:
100     #   if (p == 0) return (s == 0)
101     #   currs = s->start
102     #   maxs = s->end
103     #   if (maxs - currs != p->length) return false
104     #   currp = p->data
105     #   while currs < maxs
106     #     if (*currs != *currp) return false
107     #     ++currs
108     #     ++currp
109     #   return true
110     #
111     # registers:
112     #   currs: EDX
113     #   maxs: ESI
114     #   currp: EBX
115     #   *currs: EAX
116     #   *currp: ECX
117     #
118     # . prolog
119     55/push-EBP
120     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
121     # . save registers
122     51/push-ECX
123     52/push-EDX
124     53/push-EBX
125     56/push-ESI
126     # ESI = s
127     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           6/r32/ESI   8/disp8         .                 # copy *(EBP+8) to ESI
128     # currs/EDX = s->start
129     8b/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           2/r32/EDX   .               .                 # copy *ESI to EDX
130     # maxs/ESI = s->end
131     8b/copy                         1/mod/*+disp8   6/rm32/ESI    .           .             .           6/r32/ESI   4/disp8         .                 # copy *(ESI+4) to ESI
132     # EAX = maxs - currs
133     89/copy                         3/mod/direct    0/rm32/EAX    .           .             .           6/r32/ESI   .               .                 # copy ESI to EAX
134     29/subtract                     3/mod/direct    0/rm32/EAX    .           .             .           2/r32/EDX   .               .                 # subtract EDX from EAX
135     # EBX = p
136     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           3/r32/EBX   0xc/disp8       .                 # copy *(EBP+12) to EBX
137     # if (p != 0) goto next check
138     81          7/subop/compare     3/mod/direct    3/rm32/EBX    .           .             .           .           .               0/imm32           # compare EBX
139     75/jump-if-not-equal  $slice-equal?:nonnull-string/disp8
140 $slice-equal?:null-string:
141     # return s->start == s->end
142     3d/compare-EAX-and  0/imm32
143     74/jump-if-equal  $slice-equal?:true/disp8
144     eb/jump  $slice-equal?:false/disp8
145 $slice-equal?:nonnull-string:
146     # if (EAX != p->length) return false
147     39/compare                      0/mod/indirect  3/rm32/EBX    .           .             .           0/r32/EAX   .               .                 # compare *EBX and EAX
148     75/jump-if-not-equal  $slice-equal?:false/disp8
149     # currp/EBX = p->data
150     81          0/subop/add         3/mod/direct    3/rm32/EBX    .           .             .           .           .               4/imm32           # add to EBX
151     # EAX = ECX = 0
152     31/xor                          3/mod/direct    0/rm32/EAX    .           .             .           0/r32/EAX   .               .                 # clear EAX
153     31/xor                          3/mod/direct    1/rm32/ECX    .           .             .           1/r32/ECX   .               .                 # clear ECX
154 $slice-equal?:loop:
155     # if (currs >= maxs) return true
156     39/compare                      3/mod/direct    2/rm32/EDX    .           .             .           6/r32/ESI   .               .                 # compare EDX with ESI
157     7d/jump-if-greater-or-equal  $slice-equal?:true/disp8
158     # AL = *currp
159     8a/copy-byte                    0/mod/indirect  3/rm32/EBX    .           .             .           0/r32/AL    .               .                 # copy byte at *EBX to AL
160     # CL = *currs
161     8a/copy-byte                    0/mod/indirect  2/rm32/EDX    .           .             .           1/r32/CL    .               .                 # copy byte at *EDX to CL
162     # if (EAX != ECX) return false
163     39/compare                      3/mod/direct    0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # compare EAX and ECX
164     75/jump-if-not-equal  $slice-equal?:false/disp8
165     # ++currp
166     43/increment-EBX
167     # ++currs
168     42/increment-EDX
169     eb/jump $slice-equal?:loop/disp8
170 $slice-equal?:false:
171     b8/copy-to-EAX  0/imm32
172     eb/jump  $slice-equal?:end/disp8
173 $slice-equal?:true:
174     b8/copy-to-EAX  1/imm32
175 $slice-equal?:end:
176     # . restore registers
177     5e/pop-to-ESI
178     5b/pop-to-EBX
179     5a/pop-to-EDX
180     59/pop-to-ECX
181     # . epilog
182     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
183     5d/pop-to-EBP
184     c3/return
185 
186 test-slice-equal:
187     # - slice-equal?(slice("Abc"), "Abc") == 1
188     # . prolog
189     55/push-EBP
190     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
191     # var slice/ECX
192     68/push  _test-slice-data-3/imm32/end
193     68/push  _test-slice-data-0/imm32/start
194     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
195     # EAX = slice-equal?(ECX, "Abc")
196     # . . push args
197     68/push  "Abc"/imm32
198     51/push-ECX
199     # . . call
200     e8/call  slice-equal?/disp32
201     # . . discard args
202     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
203     # check-ints-equal(EAX, 1, msg)
204     # . . push args
205     68/push  "F - test-slice-equal"/imm32
206     68/push  1/imm32
207     50/push-EAX
208     # . . call
209     e8/call  check-ints-equal/disp32
210     # . . discard args
211     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
212     # . epilog
213     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
214     5d/pop-to-EBP
215     c3/return
216 
217 test-slice-equal-false:
218     # - slice-equal?(slice("bcd"), "Abc") == 0
219     # . prolog
220     55/push-EBP
221     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
222     # var slice/ECX
223     68/push  _test-slice-data-4/imm32/end
224     68/push  _test-slice-data-1/imm32/start
225     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
226     # EAX = slice-equal?(ECX, "Abc")
227     # . . push args
228     68/push  "Abc"/imm32
229     51/push-ECX
230     # . . call
231     e8/call  slice-equal?/disp32
232     # . . discard args
233     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
234     # check-ints-equal(EAX, 0, msg)
235     # . . push args
236     68/push  "F - test-slice-equal-false"/imm32
237     68/push  0/imm32
238     50/push-EAX
239     # . . call
240     e8/call  check-ints-equal/disp32
241     # . . discard args
242     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
243     # . epilog
244     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
245     5d/pop-to-EBP
246     c3/return
247 
248 test-slice-equal-too-long:
249     # - slice-equal?(slice("Abcd"), "Abc") == 0
250     # . prolog
251     55/push-EBP
252     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
253     # var slice/ECX
254     68/push  _test-slice-data-4/imm32/end
255     68/push  _test-slice-data-0/imm32/start
256     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
257     # EAX = slice-equal?(ECX, "Abc")
258     # . . push args
259     68/push  "Abc"/imm32
260     51/push-ECX
261     # . . call
262     e8/call  slice-equal?/disp32
263     # . . discard args
264     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
265     # check-ints-equal(EAX, 0, msg)
266     # . . push args
267     68/push  "F - test-slice-equal-too-long"/imm32
268     68/push  0/imm32
269     50/push-EAX
270     # . . call
271     e8/call  check-ints-equal/disp32
272     # . . discard args
273     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
274     # . epilog
275     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
276     5d/pop-to-EBP
277     c3/return
278 
279 test-slice-equal-too-short:
280     # - slice-equal?(slice("A"), "Abc") == 0
281     # . prolog
282     55/push-EBP
283     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
284     # var slice/ECX
285     68/push  _test-slice-data-1/imm32/end
286     68/push  _test-slice-data-0/imm32/start
287     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
288     # EAX = slice-equal?(ECX, "Abc")
289     # . . push args
290     68/push  "Abc"/imm32
291     51/push-ECX
292     # . . call
293     e8/call  slice-equal?/disp32
294     # . . discard args
295     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
296     # check-ints-equal(EAX, 0, msg)
297     # . . push args
298     68/push  "F - test-slice-equal-too-short"/imm32
299     68/push  0/imm32
300     50/push-EAX
301     # . . call
302     e8/call  check-ints-equal/disp32
303     # . . discard args
304     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
305     # . epilog
306     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
307     5d/pop-to-EBP
308     c3/return
309 
310 test-slice-equal-empty:
311     # - slice-equal?(slice(""), "Abc") == 0
312     # . prolog
313     55/push-EBP
314     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
315     # var slice/ECX
316     68/push  _test-slice-data-0/imm32/end
317     68/push  _test-slice-data-0/imm32/start
318     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
319     # EAX = slice-equal?(ECX, "Abc")
320     # . . push args
321     68/push  "Abc"/imm32
322     51/push-ECX
323     # . . call
324     e8/call  slice-equal?/disp32
325     # . . discard args
326     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
327     # check-ints-equal(EAX, 0, msg)
328     # . . push args
329     68/push  "F - test-slice-equal-empty"/imm32
330     68/push  0/imm32
331     50/push-EAX
332     # . . call
333     e8/call  check-ints-equal/disp32
334     # . . discard args
335     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
336     # . epilog
337     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
338     5d/pop-to-EBP
339     c3/return
340 
341 test-slice-equal-with-empty:
342     # - slice-equal?(slice("Ab"), "") == 0
343     # . prolog
344     55/push-EBP
345     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
346     # var slice/ECX
347     68/push  _test-slice-data-2/imm32/end
348     68/push  _test-slice-data-0/imm32/start
349     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
350     # EAX = slice-equal?(ECX, "")
351     # . . push args
352     68/push  ""/imm32
353     51/push-ECX
354     # . . call
355     e8/call  slice-equal?/disp32
356     # . . discard args
357     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
358     # check-ints-equal(EAX, 0, msg)
359     # . . push args
360     68/push  "F - test-slice-equal-with-empty"/imm32
361     68/push  0/imm32
362     50/push-EAX
363     # . . call
364     e8/call  check-ints-equal/disp32
365     # . . discard args
366     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
367     # . epilog
368     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
369     5d/pop-to-EBP
370     c3/return
371 
372 test-slice-equal-empty-with-empty:
373     # - slice-equal?(slice(""), "") == 1
374     # . prolog
375     55/push-EBP
376     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
377     # var slice/ECX
378     68/push  _test-slice-data-0/imm32/end
379     68/push  _test-slice-data-0/imm32/start
380     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
381     # EAX = slice-equal?(ECX, "")
382     # . . push args
383     68/push  ""/imm32
384     51/push-ECX
385     # . . call
386     e8/call  slice-equal?/disp32
387     # . . discard args
388     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
389     # check-ints-equal(EAX, 1, msg)
390     # . . push args
391     68/push  "F - test-slice-equal-empty-with-empty"/imm32
392     68/push  1/imm32
393     50/push-EAX
394     # . . call
395     e8/call  check-ints-equal/disp32
396     # . . discard args
397     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
398     # . epilog
399     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
400     5d/pop-to-EBP
401     c3/return
402 
403 test-slice-equal-with-null:
404     # - slice-equal?(slice("Ab"), null) == 0
405     # . prolog
406     55/push-EBP
407     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
408     # var slice/ECX
409     68/push  _test-slice-data-2/imm32/end
410     68/push  _test-slice-data-0/imm32/start
411     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
412     # EAX = slice-equal?(ECX, 0)
413     # . . push args
414     68/push  0/imm32
415     51/push-ECX
416     # . . call
417     e8/call  slice-equal?/disp32
418     # . . discard args
419     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
420     # check-ints-equal(EAX, 0, msg)
421     # . . push args
422     68/push  "F - test-slice-equal-with-null"/imm32
423     68/push  0/imm32
424     50/push-EAX
425     # . . call
426     e8/call  check-ints-equal/disp32
427     # . . discard args
428     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
429     # . epilog
430     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
431     5d/pop-to-EBP
432     c3/return
433 
434 slice-starts-with?:  # s : (address slice), head : (address string) -> EAX : boolean
435     # pseudocode
436     #   lenh = head->length
437     #   if (lenh > s->end - s->start) return false
438     #   i = 0
439     #   currs = s->start
440     #   currp = head->data
441     #   while i < lenh
442     #     if (*currs != *currh) return false
443     #     ++i
444     #     ++currs
445     #     ++currh
446     #   return true
447     #
448     # registers:
449     #   currs: ESI
450     #   currh: EDI
451     #   *currs: EAX
452     #   *currh: EBX
453     #   i: ECX
454     #   lenh: EDX
455     #
456     # . prolog
457     55/push-EBP
458     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
459     # . save registers
460     51/push-ECX
461     52/push-EDX
462     53/push-EBX
463     56/push-ESI
464     57/push-EDI
465     # ESI = s
466     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           6/r32/ESI   8/disp8         .                 # copy *(EBP+8) to ESI
467     # ECX = s->end - s->start
468     8b/copy                         1/mod/*+disp8   6/rm32/ESI    .           .             .           1/r32/ECX   4/disp8         .                 # copy *(ESI+4) to ECX
469     2b/subtract                     0/mod/indirect  6/rm32/ESI    .           .             .           1/r32/ECX   .               .                 # subtract *ESI from ECX
470     # EDI = head
471     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           7/r32/EDI   0xc/disp8       .                 # copy *(EBP+12) to EDI
472     # lenh/EDX = head->length
473     8b/copy                         0/mod/indirect  7/rm32/EDI    .           .             .           2/r32/EDX   .               .                 # copy *EDI to EDX
474     # if (lenh > s->end - s->start) return false
475     39/compare                      3/mod/direct    2/rm32/EDX    .           .             .           1/r32/ECX   .               .                 # compare EDX with ECX
476     7f/jump-if-greater  $slice-starts-with?:false/disp8
477     # currs/ESI = s->start
478     8b/subtract                     0/mod/indirect  6/rm32/ESI    .           .             .           6/r32/ESI   .               .                 # copy *ESI to ESI
479     # currh/EDI = head->data
480     81          0/subop/add         3/mod/direct    7/rm32/EDI    .           .             .           .           .               4/imm32           # add to EDI
481     # i/ECX = 0
482     31/xor                          3/mod/direct    1/rm32/ECX    .           .             .           1/r32/ECX   .               .                 # clear ECX
483     # EAX = EBX = 0
484     31/xor                          3/mod/direct    0/rm32/EAX    .           .             .           0/r32/EAX   .               .                 # clear EAX
485     31/xor                          3/mod/direct    3/rm32/EBX    .           .             .           3/r32/EBX   .               .                 # clear EBX
486 $slice-starts-with?:loop:
487     # if (i >= lenh) return true
488     39/compare                      3/mod/direct    1/rm32/ECX    .           .             .           2/r32/EDX   .               .                 # compare ECX with EDX
489     7d/jump-if-greater-or-equal  $slice-starts-with?:true/disp8
490     # AL = *currs
491     8a/copy-byte                    0/mod/indirect  6/rm32/ESI    .           .             .           0/r32/AL    .               .                 # copy byte at *ESI to AL
492     # BL = *currh
493     8a/copy-byte                    0/mod/indirect  7/rm32/EDI    .           .             .           3/r32/BL    .               .                 # copy byte at *EDI to BL
494     # if (*currs != *currh) return false
495     39/compare                      3/mod/direct    0/rm32/EAX    .           .             .           3/r32/EBX   .               .                 # compare EAX and EBX
496     75/jump-if-not-equal  $slice-starts-with?:false/disp8
497     # ++i
498     41/increment-ECX
499     # ++currs
500     46/increment-ESI
501     # ++currh
502     47/increment-EDI
503     eb/jump $slice-starts-with?:loop/disp8
504 $slice-starts-with?:true:
505     b8/copy-to-EAX  1/imm32
506     eb/jump  $slice-starts-with?:end/disp8
507 $slice-starts-with?:false:
508     b8/copy-to-EAX  0/imm32
509 $slice-starts-with?:end:
510     # . restore registers
511     5f/pop-to-EDI
512     5e/pop-to-ESI
513     5b/pop-to-EBX
514     5a/pop-to-EDX
515     59/pop-to-ECX
516     # . epilog
517     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
518     5d/pop-to-EBP
519     c3/return
520 
521 test-slice-starts-with-single-character:
522     # - slice-starts-with?(slice("Abc"), "A") == 1
523     # . prolog
524     55/push-EBP
525     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
526     # var slice/ECX
527     68/push  _test-slice-data-3/imm32/end
528     68/push  _test-slice-data-0/imm32/start
529     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
530     # EAX = slice-starts-with?(ECX, "A")
531     # . . push args
532     68/push  "A"/imm32
533     51/push-ECX
534     # . . call
535     e8/call  slice-starts-with?/disp32
536     # . . discard args
537     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
538     # check-ints-equal(EAX, 1, msg)
539     # . . push args
540     68/push  "F - test-slice-starts-with-single-character"/imm32
541     68/push  1/imm32
542     50/push-EAX
543     # . . call
544     e8/call  check-ints-equal/disp32
545     # . . discard args
546     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
547     # . epilog
548     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
549     5d/pop-to-EBP
550     c3/return
551 
552 test-slice-starts-with-empty-string:
553     # - slice-starts-with?(slice("Abc"), "") == 1
554     # . prolog
555     55/push-EBP
556     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
557     # var slice/ECX
558     68/push  _test-slice-data-3/imm32/end
559     68/push  _test-slice-data-0/imm32/start
560     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
561     # EAX = slice-starts-with?(ECX, "")
562     # . . push args
563     68/push  ""/imm32
564     51/push-ECX
565     # . . call
566     e8/call  slice-starts-with?/disp32
567     # . . discard args
568     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
569     # check-ints-equal(EAX, 1, msg)
570     # . . push args
571     68/push  "F - test-slice-starts-with-empty-string"/imm32
572     68/push  1/imm32
573     50/push-EAX
574     # . . call
575     e8/call  check-ints-equal/disp32
576     # . . discard args
577     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
578     # . epilog
579     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
580     5d/pop-to-EBP
581     c3/return
582 
583 test-slice-starts-with-multiple-characters:
584     # - slice-starts-with?(slice("Abc"), "Ab") == 1
585     # . prolog
586     55/push-EBP
587     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
588     # var slice/ECX
589     68/push  _test-slice-data-3/imm32/end
590     68/push  _test-slice-data-0/imm32/start
591     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
592     # EAX = slice-starts-with?(ECX, "Ab")
593     # . . push args
594     68/push  "Ab"/imm32
595     51/push-ECX
596     # . . call
597     e8/call  slice-starts-with?/disp32
598     # . . discard args
599     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
600     # check-ints-equal(EAX, 1, msg)
601     # . . push args
602     68/push  "F - test-slice-starts-with-multiple-characters"/imm32
603     68/push  1/imm32
604     50/push-EAX
605     # . . call
606     e8/call  check-ints-equal/disp32
607     # . . discard args
608     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
609     # . epilog
610     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
611     5d/pop-to-EBP
612     c3/return
613 
614 test-slice-starts-with-entire-string:
615     # - slice-starts-with?(slice("Abc"), "Abc") == 1
616     # . prolog
617     55/push-EBP
618     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
619     # var slice/ECX
620     68/push  _test-slice-data-3/imm32/end
621     68/push  _test-slice-data-0/imm32/start
622     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
623     # EAX = slice-starts-with?(ECX, "Abc")
624     # . . push args
625     68/push  "Abc"/imm32
626     51/push-ECX
627     # . . call
628     e8/call  slice-starts-with?/disp32
629     # . . discard args
630     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
631     # check-ints-equal(EAX, 1, msg)
632     # . . push args
633     68/push  "F - test-slice-starts-with-entire-string"/imm32
634     68/push  1/imm32
635     50/push-EAX
636     # . . call
637     e8/call  check-ints-equal/disp32
638     # . . discard args
639     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
640     # . epilog
641     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
642     5d/pop-to-EBP
643     c3/return
644 
645 test-slice-starts-with-fails:
646     # - slice-starts-with?(slice("Abc"), "Abd") == 1
647     # . prolog
648     55/push-EBP
649     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
650     # var slice/ECX
651     68/push  _test-slice-data-3/imm32/end
652     68/push  _test-slice-data-0/imm32/start
653     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
654     # EAX = slice-starts-with?(ECX, "Abd")
655     # . . push args
656     68/push  "Abd"/imm32
657     51/push-ECX
658     # . . call
659     e8/call  slice-starts-with?/disp32
660     # . . discard args
661     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
662     # check-ints-equal(EAX, 0, msg)
663     # . . push args
664     68/push  "F - test-slice-starts-with-fails"/imm32
665     68/push  0/imm32
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     # . epilog
672     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
673     5d/pop-to-EBP
674     c3/return
675 
676 test-slice-starts-with-fails-2:
677     # - slice-starts-with?(slice("Abc"), "Ac") == 1
678     # . prolog
679     55/push-EBP
680     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
681     # var slice/ECX
682     68/push  _test-slice-data-3/imm32/end
683     68/push  _test-slice-data-0/imm32/start
684     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
685     # EAX = slice-starts-with?(ECX, "Ac")
686     # . . push args
687     68/push  "Ac"/imm32
688     51/push-ECX
689     # . . call
690     e8/call  slice-starts-with?/disp32
691     # . . discard args
692     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
693     # check-ints-equal(EAX, 0, msg)
694     # . . push args
695     68/push  "F - test-slice-starts-with-fails-2"/imm32
696     68/push  0/imm32
697     50/push-EAX
698     # . . call
699     e8/call  check-ints-equal/disp32
700     # . . discard args
701     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
702     # . epilog
703     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
704     5d/pop-to-EBP
705     c3/return
706 
707 write-slice:  # out : (address buffered-file), s : (address slice)
708     # . prolog
709     55/push-EBP
710     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
711     # . save registers
712     50/push-EAX
713     51/push-ECX
714     52/push-EDX
715     53/push-EBX
716     56/push-ESI
717     57/push-EDI
718     # ESI = s
719     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           6/r32/ESI   0xc/disp8       .                 # copy *(EBP+12) to ESI
720     # curr/ECX = s->start
721     8b/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           1/r32/ECX   .               .                 # copy *ESI to ECX
722     # max/ESI = s->end
723     8b/copy                         1/mod/*+disp8   6/rm32/ESI    .           .             .           6/r32/ESI   4/disp8         .                 # copy *(ESI+4) to ESI
724     # EDI = out
725     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .                         7/r32/EDI   8/disp8         .                 # copy *(EBP+8) to EDI
726     # EDX = out->length
727     8b/copy                         1/mod/*+disp8   7/rm32/EDI    .           .             .           2/r32/EDX   0xc/disp8       .                 # copy *(EDI+12) to EDX
728     # EBX = out->write
729     8b/copy                         1/mod/*+disp8   7/rm32/EDI    .           .             .           3/r32/EBX   4/disp8         .                 # copy *(EDI+4) to EBX
730 $write-slice:loop:
731     # if (curr >= max) break
732     39/compare                      3/mod/direct    1/rm32/ECX    .           .             .           6/r32/ESI   .               .                 # compare ECX with ESI
733     7d/jump-if-greater-or-equal  $write-slice:loop-end/disp8
734     # if (out->write >= out->length) flush and clear out's stream
735     39/compare                      3/mod/direct    3/rm32/EBX    .           .             .           2/r32/EDX   .               .                 # compare EBX with EDX
736     7c/jump-if-lesser  $write-slice:to-stream/disp8
737     # . persist out->write
738     89/copy                         1/mod/*+disp8   7/rm32/EDI    .           .             .           3/r32/EBX   4/disp8         .                 # copy EBX to *(EDI+4)
739     # . flush(out)
740     # . . push args
741     57/push-EDI
742     # . . call
743     e8/call  flush/disp32
744     # . . discard args
745     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
746     # . clear-stream(stream = out+4)
747     # . . push args
748     8d/copy-address                 1/mod/*+disp8   7/rm32/EDI    .           .             .           0/r32/EAX   4/disp8         .                 # copy EDI+4 to EAX
749     50/push-EAX
750     # . . call
751     e8/call  clear-stream/disp32
752     # . . discard args
753     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
754     # . out->write must now be 0; update its cache at EBX
755     31/xor                          3/mod/direct    3/rm32/EBX    .           .             .           3/r32/EBX   .               .                 # clear EBX
756 $write-slice:to-stream:
757     # out->data[out->write] = *in
758     # . AL = *in
759     31/xor                          3/mod/direct    0/rm32/EAX    .           .             .           0/r32/EAX   .               .                 # clear EAX
760     8a/copy-byte                    0/mod/indirect  1/rm32/ECX    .           .             .           0/r32/AL    .               .                 # copy byte at *ECX to AL
761     # . out->data[out->write] = AL
762     88/copy-byte                    1/mod/*+disp8   4/rm32/sib    7/base/EDI  3/index/EBX   .           0/r32/AL    0x10/disp8      .                 # copy AL to *(EDI+EBX+16)
763     # ++out->write
764     43/increment-EBX
765     # ++in
766     41/increment-ECX
767     eb/jump  $write-slice:loop/disp8
768 $write-slice:loop-end:
769     # persist necessary variables from registers
770     89/copy                         1/mod/*+disp8   7/rm32/EDI    .           .             .           3/r32/EBX   4/disp8         .                 # copy EBX to *(EDI+4)
771 $write-slice:end:
772     # . restore registers
773     5f/pop-to-EDI
774     5e/pop-to-ESI
775     5b/pop-to-EBX
776     5a/pop-to-EDX
777     59/pop-to-ECX
778     58/pop-to-EAX
779     # . epilog
780     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
781     5d/pop-to-EBP
782     c3/return
783 
784 test-write-slice:
785     # . prolog
786     55/push-EBP
787     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
788     # setup
789     # . clear-stream(_test-stream)
790     # . . push args
791     68/push  _test-stream/imm32
792     # . . call
793     e8/call  clear-stream/disp32
794     # . . discard args
795     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
796     # . clear-stream(_test-buffered-file+4)
797     # . . push args
798     b8/copy-to-EAX  _test-buffered-file/imm32
799     05/add-to-EAX  4/imm32
800     50/push-EAX
801     # . . call
802     e8/call  clear-stream/disp32
803     # . . discard args
804     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
805     # var slice/ECX = "Abc"
806     68/push  _test-slice-data-3/imm32/end
807     68/push  _test-slice-data-0/imm32/start
808     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
809     # write-slice(_test-buffered-file, slice)
810     # . . push args
811     51/push-ECX
812     68/push  _test-buffered-file/imm32
813     # . . call
814     e8/call  write-slice/disp32
815     # . . discard args
816     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
817     # flush(_test-buffered-file)
818     # . . push args
819     68/push  _test-buffered-file/imm32
820     # . . call
821     e8/call  flush/disp32
822     # . . discard args
823     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
824     # check-stream-equal(_test-stream, "Abc", msg)
825     # . . push args
826     68/push  "F - test-write-slice"/imm32
827     68/push  "Abc"/imm32
828     68/push  _test-stream/imm32
829     # . . call
830     e8/call  check-stream-equal/disp32
831     # . . discard args
832     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
833     # . epilog
834     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
835     5d/pop-to-EBP
836     c3/return
837 
838 # copy a slice into a new (dynamically allocated) string
839 slice-to-string:  # ad : (address allocation-descriptor), in : (address slice) -> out/EAX : (address array)
840     # . prolog
841     55/push-EBP
842     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
843     # . save registers
844     51/push-ECX
845     52/push-EDX
846     53/push-EBX
847     56/push-ESI
848     # ESI = in
849     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           6/r32/ESI   0xc/disp8       .                 # copy *(EBP+12) to ESI
850     # curr/EDX = in->start
851     8b/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           2/r32/EDX   .               .                 # copy *ESI to EDX
852     # max/EBX = in->end
853     8b/copy                         1/mod/*+disp8   6/rm32/ESI    .           .             .           3/r32/EBX   4/disp8         .                 # copy *(ESI+4) to EBX
854     # size/ECX = max - curr + 4  # total size of output string (including the initial length)
855     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           3/r32/EBX   .               .                 # copy EBX to ECX
856     29/subtract                     3/mod/direct    1/rm32/ECX    .           .             .           2/r32/EDX   .               .                 # subtract EDX from ECX
857     81          0/subop/add         3/mod/direct    1/rm32/ECX    .           .             .           .           .               4/imm32           # add to ECX
858     # out/EAX = allocate(ad, size)
859     # . . push args
860     51/push-ECX
861     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
862     # . . call
863     e8/call  allocate/disp32
864     # . . discard args
865     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
866     # if (EAX == 0) abort
867     3d/compare-EAX-and  0/imm32
868     74/jump-if-equal  $slice-to-string:abort/disp8
869     # *out = size-4
870     89/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy ECX to *EAX
871     81          5/subop/subtract    0/mod/indirect  0/rm32/EAX    .           .             .           .           .               4/imm32           # subtract 4 from *EAX
872     # save out
873     50/push-EAX
874     # EAX = _append-4(EAX+4, EAX+size, curr, max)  # clobbering ECX
875     # . . push args
876     53/push-EBX
877     52/push-EDX
878     # . . push EAX+size (clobbering ECX)
879     01/add                          3/mod/direct    1/rm32/ECX    .           .             .           0/r32/EAX   .               .                 # add EAX to ECX
880     51/push-ECX
881     # . . push EAX+4 (clobbering EAX)
882     81          0/subop/add         3/mod/direct    0/rm32/EAX    .           .             .           .           .               4/imm32           # add to EAX
883     50/push-EAX
884     # . . call
885     e8/call  _append-4/disp32
886     # . . discard args
887     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x10/imm32        # add to ESP
888     # restore out (assumes _append-4 can't error)
889     58/pop-to-EAX
890 $slice-to-string:end:
891     # . restore registers
892     5e/pop-to-ESI
893     5b/pop-to-EBX
894     5a/pop-to-EDX
895     59/pop-to-ECX
896     # . epilog
897     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
898     5d/pop-to-EBP
899     c3/return
900 
901 $slice-to-string:abort:
902     # . _write(2/stderr, error)
903     # . . push args
904     68/push  "slice-to-string: out of space"/imm32
905     68/push  2/imm32/stderr
906     # . . call
907     e8/call  _write/disp32
908     # . . discard args
909     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
910     # . syscall(exit, 1)
911     bb/copy-to-EBX  1/imm32
912     b8/copy-to-EAX  1/imm32/exit
913     cd/syscall  0x80/imm8
914     # never gets here
915 
916 test-slice-to-string:
917     # . prolog
918     55/push-EBP
919     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
920     # var slice/ECX = "Abc"
921     68/push  _test-slice-data-3/imm32/end
922     68/push  _test-slice-data-0/imm32/start
923     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
924     # EAX = slice-to-string(Heap, slice)
925     # . . push args
926     51/push-ECX
927     68/push  Heap/imm32
928     # . . call
929     e8/call  slice-to-string/disp32
930     # . . discard args
931     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
932 +-- 26 lines: #?     # dump word-slice -----------------------------------------------------------------------------------------------------------------------
958     # EAX = string-equal?(EAX, "Abc")
959     # . . push args
960     68/push  "Abc"/imm32
961     50/push-EAX
962     # . . call
963     e8/call  string-equal?/disp32
964     # . . discard args
965     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
966     # check-ints-equal(EAX, 1, msg)
967     # . . push args
968     68/push  "F - test-slice-to-string"/imm32
969     68/push  1/imm32/true
970     50/push-EAX
971     # . . call
972     e8/call  check-ints-equal/disp32
973     # . . discard args
974     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
975     # . epilog
976     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
977     5d/pop-to-EBP
978     c3/return
979 
980 == data
981 
982 _test-slice-data-0:
983     41/A
984 _test-slice-data-1:
985     62/b
986 _test-slice-data-2:
987     63/c
988 _test-slice-data-3:
989     64/d
990 _test-slice-data-4:
991 
992 # . _. vim:nowrap:textwidth=0