Stephen Pelc <
stephen@vfxforth.com> writes:
On 17 Jul 2024 at 08:47:45 BST, "dxf" <dxforth@gmail.com> wrote:
>
DEFER may not be as fast as a directly patched definition but neither
has that prevented a generation from using it.
>
At least on x64 and CISC CPUs, calling a deferred word is just
CALL [] foo
rather than
CALL foo
>
The difference on x64 is one byte and a a few (hardware and cache
dependent) cycles.
It's a bit more in Gforth (see below), but indeed, the difference is
small.
IMHO Forward referencing and resolving words are likely just to be
wrappers for syntactic sugar around DEFER and IS.
As I demonstrated in <
2024Jul15.152917@mips.complang.tuwien.ac.at>,
Gforth's FORWARD uses direct calls in compiled words. Maybe the
example was unclear. Here is a simpler one:
forward x1
: y1 x1 ;
: x1 ;
y1
defer x2
: y2 x2 ;
: z2 ;
' z2 is x2
z2
cr see-code y1
cr see-code y2
Here's what the SEE-CODE calls produce:
cr see-code y1
$7F411D19D810 call 1->1
$7F411D19D818 x1
0x00007f411ce3f2c0: mov 0x8(%rbx),%rax
0x00007f411ce3f2c4: sub $0x8,%r14
0x00007f411ce3f2c8: add $0x10,%rbx
0x00007f411ce3f2cc: mov %rbx,(%r14)
0x00007f411ce3f2cf: mov %rax,%rbx
0x00007f411ce3f2d2: mov (%rbx),%rax
0x00007f411ce3f2d5: jmp *%rax
$7F411D19D820 ;s 1->1
0x00007f411ce3f2d7: mov (%r14),%rbx
0x00007f411ce3f2da: add $0x8,%r14
0x00007f411ce3f2de: mov (%rbx),%rax
0x00007f411ce3f2e1: jmp *%rax
ok
cr see-code y2
$7F411D19D8B0 lit-perform 1->1
$7F411D19D8B8 x2
0x00007f411ce3f2f0: mov 0x8(%rbx),%rax
0x00007f411ce3f2f4: add $0x8,%rbx
0x00007f411ce3f2f8: mov (%rax),%rdx
0x00007f411ce3f2fb: mov -0x10(%rdx),%rax
0x00007f411ce3f2ff: jmp *%rax
$7F411D19D8C0 ;s 1->1
0x00007f411ce3f301: mov (%r14),%rbx
0x00007f411ce3f304: add $0x8,%r14
0x00007f411ce3f308: mov (%rbx),%rax
0x00007f411ce3f30b: jmp *%rax
So the LIT-PERFORM in Y2 looks shorter, but it calls
the docol of Z2:
docol: 19 discode
0x00005647dfff8a08 <gforth_engine+104>: add $0x8,%rbx
0x00005647dfff8a0c <gforth_engine+108>: sub $0x8,%r14
0x00005647dfff8a10 <gforth_engine+112>: mov %rbx,(%r14)
0x00005647dfff8a13 <gforth_engine+115>: mov %rdx,%rbx
0x00005647dfff8a16 <gforth_engine+118>: mov (%rbx),%rax
0x00005647dfff8a19 <gforth_engine+121>: jmp *%rax
before it executes the code of Z2. By contrast, the CALL in Y1
directly continues with the code of X1. So overall, the
LIT-PERFORM+DOCOL cost 5+6=11 instructions, while the CALL costs 7
instructions.
And before we forget, here we see clearly that the FORWARD is resolved
to a direct call (CALL), not the code generated for a deferred word.
- anton
-- M. Anton Ertl http://www.complang.tuwien.ac.at/anton/home.htmlcomp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html New standard: https://forth-standard.org/ EuroForth 2024: https://euro.theforth.net