• nest-sys revisited

    From albert@albert@spenarnc.xs4all.nl to comp.lang.forth on Thu Mar 13 17:19:30 2025
    From Newsgroup: comp.lang.forth

    Apologize, for bad mouthing nested-sys in the coroutine discussion.
    (not that I like this concept).

    In the ISO 94 document the concept of nest-sys is indeed needed.
    It is present in the convoluted explanation of DOES>.
    A more reasonable, not overly clever, implementation of the concept of
    a poor man's object is META. Remember: CREATE DOES> words are a data
    structure coupled with a single behaviour, a kind of object.

    This is META.
    \ ( xtb xtd "name" -- ) generate DEA for "name".

    It is most easily explained via an example:

    : CONSTANT CREATE , DOES> @ ;

    META replaces CREATE and DOES> meanwhile not introducing anything
    new.

    The above examples becomes using META :

    :NONAME , ; :NONAME @ ; META CONSTANT

    The specification of META is

    \ ( xtb xtd "name" -- ) generate DEA for "name".

    The dictionary entry (e.g. CONSTANT) identified by "name" does
    the following:

    On compilation :
    (Think `` 12 CONSTANT ORANGUTAN ''
    It parses a name and generates a dictionary entry for it.
    xtb is executed and the base address is retained.

    On execution of the resulting word:
    xtd is executed with on the stack the base address.

    The mystification disappears. Nowhere is nested-sys in sight.

    I prefer { } over :NONAME.

    My favorite is

    { } { } META DATA

    Hint :
    : VARIABLE DATA 0 , ;

    Groetjes Albert
    --
    Temu exploits Christians: (Disclaimer, only 10 apostles)
    Last Supper Acrylic Suncatcher - 15Cm Round Stained Glass- Style Wall
    Art For Home, Office And Garden Decor - Perfect For Windows, Bars,
    And Gifts For Friends Family And Colleagues.
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From dxf@dxforth@gmail.com to comp.lang.forth on Fri Mar 14 12:26:56 2025
    From Newsgroup: comp.lang.forth

    On 14/03/2025 3:19 am, albert@spenarnc.xs4all.nl wrote:
    Apologize, for bad mouthing nested-sys in the coroutine discussion.
    (not that I like this concept).

    In the ISO 94 document the concept of nest-sys is indeed needed.
    ...

    Unavoidable really. Nesting aka subroutine call - the process of
    calling a function and when it completes, returning to the caller -
    is a basic computing concept. In forth 'nest-sys' represents the
    information necessary to facilitate that return. It should not be
    confused with invoking a function i.e. 'xt' EXECUTE.

    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From albert@albert@spenarnc.xs4all.nl to comp.lang.forth on Fri Mar 14 13:46:51 2025
    From Newsgroup: comp.lang.forth

    In article <8d760e814c0d0342eb9beaa0d271a6f1d1271e3a@i2pn2.org>,
    dxf <dxforth@gmail.com> wrote:
    On 14/03/2025 3:19 am, albert@spenarnc.xs4all.nl wrote:
    Apologize, for bad mouthing nested-sys in the coroutine discussion.
    (not that I like this concept).

    In the ISO 94 document the concept of nest-sys is indeed needed.
    ...

    Unavoidable really. Nesting aka subroutine call - the process of
    calling a function and when it completes, returning to the caller -
    is a basic computing concept. In forth 'nest-sys' represents the
    information necessary to facilitate that return. It should not be
    confused with invoking a function i.e. 'xt' EXECUTE.

    I've shown that the concept of nest-sys is avoidable for a language
    that has the capabilities of Forth with a slight reorganisation of
    the CREATE DOES> construction.

    nest-sys is a ghost. You know it must be there, but only an
    implementor has to deal with it. Unless you stick to CREATE DOES>,
    you call this unavoidable, I don't.

    Groetjes Albert.
    --
    Temu exploits Christians: (Disclaimer, only 10 apostles)
    Last Supper Acrylic Suncatcher - 15Cm Round Stained Glass- Style Wall
    Art For Home, Office And Garden Decor - Perfect For Windows, Bars,
    And Gifts For Friends Family And Colleagues.
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From dxf@dxforth@gmail.com to comp.lang.forth on Sat Mar 15 09:34:27 2025
    From Newsgroup: comp.lang.forth

    On 14/03/2025 11:46 pm, albert@spenarnc.xs4all.nl wrote:
    In article <8d760e814c0d0342eb9beaa0d271a6f1d1271e3a@i2pn2.org>,
    dxf <dxforth@gmail.com> wrote:
    On 14/03/2025 3:19 am, albert@spenarnc.xs4all.nl wrote:
    Apologize, for bad mouthing nested-sys in the coroutine discussion.
    (not that I like this concept).

    In the ISO 94 document the concept of nest-sys is indeed needed.
    ...

    Unavoidable really. Nesting aka subroutine call - the process of
    calling a function and when it completes, returning to the caller -
    is a basic computing concept. In forth 'nest-sys' represents the
    information necessary to facilitate that return. It should not be
    confused with invoking a function i.e. 'xt' EXECUTE.

    I've shown that the concept of nest-sys is avoidable for a language
    that has the capabilities of Forth with a slight reorganisation of
    the CREATE DOES> construction.

    nest-sys is a ghost. You know it must be there, but only an
    implementor has to deal with it. Unless you stick to CREATE DOES>,
    you call this unavoidable, I don't.

    For whom is nest-sys a problem? Not Standard users. I've used
    CREATE DOES> and don't recall thinking about nest-sys once. Same
    goes for : and ; It only becomes an issue if a user does something
    not covered by the Standard e.g. R> DROP to discard a nest-sys.



    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From Hans Bezemer@the.beez.speaks@gmail.com to comp.lang.forth on Sun Mar 16 16:30:33 2025
    From Newsgroup: comp.lang.forth

    On 14-03-2025 02:26, dxf wrote:
    On 14/03/2025 3:19 am, albert@spenarnc.xs4all.nl wrote:
    Apologize, for bad mouthing nested-sys in the coroutine discussion.
    (not that I like this concept).

    In the ISO 94 document the concept of nest-sys is indeed needed.
    ...

    Unavoidable really. Nesting aka subroutine call - the process of
    calling a function and when it completes, returning to the caller -
    is a basic computing concept. In forth 'nest-sys' represents the
    information necessary to facilitate that return. It should not be
    confused with invoking a function i.e. 'xt' EXECUTE.

    I agree with most of what you say - except EXECUTE, a "function" can be called, but has to return *somewhere* - otherwise it is a BRANCH (jump).

    But that aside. I now know where I went wrong - and I'm sorry for the confusion. I keep forgetting Forth is a SYSTEM standard - and not a
    LANGUAGE standard.

    In (classic) Forth, almost every single word is a subroutine call. When subroutine threaded, you see a long list of CALLs being compiled. Not so
    in 4tH. In 4tH MOST words are primitives that are not called, but simply
    the next in line to be executed. Hence, most words in 4tH don't deal
    with the Return stack - except those who are CALLed, EXECUTEd or EXITed.

    Now, I guess this is also largely true for native code Forth compilers,
    but direct or indirect threaded Forths - I guess that the placing of
    nest-sys on the Return stack is mostly in the hands of the inner
    interpreter. So yes, Albert - I understand what you're saying now.

    So - I'm sorry for the confusion I caused.

    Hans Bezemer

    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From dxf@dxforth@gmail.com to comp.lang.forth on Mon Mar 17 12:14:38 2025
    From Newsgroup: comp.lang.forth

    On 17/03/2025 2:30 am, Hans Bezemer wrote:
    On 14-03-2025 02:26, dxf wrote:
    On 14/03/2025 3:19 am, albert@spenarnc.xs4all.nl wrote:
    Apologize, for bad mouthing nested-sys in the coroutine discussion.
    (not that I like this concept).

    In the ISO 94 document the concept of nest-sys is indeed needed.
    ...

    Unavoidable really.  Nesting aka subroutine call - the process of
    calling a function and when it completes, returning to the caller -
    is a basic computing concept.  In forth 'nest-sys' represents the
    information necessary to facilitate that return.  It should not be
    confused with invoking a function i.e. 'xt' EXECUTE.

    I agree with most of what you say - except EXECUTE, a "function" can be called, but has to return *somewhere* - otherwise it is a BRANCH (jump).

    Would you agree 'nest-sys' are peculiar to colon definitions. That
    EXECUTE is a different class of function. It's not doing a 'call'
    as such and not leaving anything on the 'return stack'?

    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From anton@anton@mips.complang.tuwien.ac.at (Anton Ertl) to comp.lang.forth on Mon Mar 17 06:12:38 2025
    From Newsgroup: comp.lang.forth

    dxf <dxforth@gmail.com> writes:
    Would you agree 'nest-sys' are peculiar to colon definitions. That
    EXECUTE is a different class of function. It's not doing a 'call'
    as such and not leaving anything on the 'return stack'?

    That's certainly the case for threaded-code implementations.

    For native-code implementations the implementation of EXECUTE is
    usually an indirect call; sometimes an indirect tail-call, i.e. a
    jump.

    In VFX64 5.43:

    : foo execute ; ok
    see foo
    FOO
    ( 0050A250 488BD3 ) MOV RDX, RBX
    ( 0050A253 488B5D00 ) MOV RBX, [RBP]
    ( 0050A257 488D6D08 ) LEA RBP, [RBP+08]
    ( 0050A25B 48FFD2 ) CALL RDX
    ( 0050A25E C3 ) RET/NEXT

    However:

    see execute
    EXECUTE
    ( 004211B0 53 ) PUSH RBX
    ( 004211B1 488B5D00 ) MOV RBX, [RBP]
    ( 004211B5 488D6D08 ) LEA RBP, [RBP+08]
    ( 004211B9 C3 ) RET/NEXT
    ( 10 bytes, 4 instructions )

    The push-ret combination is an extremely slow form of an indirect
    jump; so where is the return address (nest-sys) here? It's the return
    address of the surrounding call. E.g., if you do

    ' + ' execute foo

    it's the call in FOO.


    SwiftForth 4.0.0-RC89:

    see foo
    4519B7 4028CB ( EXECUTE ) JMP E90F0FFBFF ok

    That's a tail-call to EXECUTE. When EXECUTE is not tail-called, the
    code of EXECUTE is invoked with call:

    : bar execute . ; ok see bar 4519D3 4028CB ( EXECUTE ) CALL E8F30EFBFF
    4519D8 40B043 ( . ) JMP E96696FBFF ok

    see execute
    4028CB RBX RCX MOV 488BCB
    4028CE 0 [RBP] RBX MOV 488B5D00
    4028D2 8 [RBP] RBP LEA 488D6D08
    4028D6 4028DD JRCXZ E305
    4028D8 RDI RCX ADD 4801F9
    4028DB RCX JMP FFE1
    4028DD RET C3 ok

    This special-cases the 0 EXECUTE case as NOOP, and also adds an offset
    (the image start?) to the xt before performing the indirect jump, but
    if you ignore those parts, this EXECUTE does the same things as VFX's,
    except that it uses the much faster indirect jmp rather than push-ret.


    lxf 1.7-172-983:
    see foo
    8692BC4 8050E6E 11 88C8000 5 normal FOO

    8050E6E 8BC3 mov eax , ebx
    8050E70 8B5D00 mov ebx , [ebp]
    8050E73 8D6D04 lea ebp , [ebp+4h]
    8050E76 FFD0 call eax
    8050E78 C3 ret near

    Here the EXECUTE is compiled inline and essentially implemented as
    indirect call. lxf does not perform tail-call optimization.

    see execute
    868E2FC 88D6B47 11 88D475B 92 prim EXECUTE

    88D6B47 8BC3 mov eax , ebx
    88D6B49 8B5D00 mov ebx , [ebp]
    88D6B4C 8D6D04 lea ebp , [ebp+4h]
    88D6B4F FFD0 call eax
    88D6B51 C3 ret near

    The same code as FOO; after all, both words do the same thing.


    iForth 5.1-mini (I think):

    FORTH> ' foo idis
    $10226000 : foo 488BC04883ED088F4500 H.@H.m..E. $1022600A pop rbx 5B [
    $1022600B or rbx, rbx 4809DB H.[
    $1022600E je $10226016 offset NEAR
    0F8402000000 ...... $10226014 call rbx FFD3 .S
    $10226016 ; 488B45004883C508FFE0 H.E.H.E..` ok

    The use of call here is interesting, because iForth uses RSP as
    data-stack pointer (e.g., the "pop rbx" moves the xt into rbx) and rbp
    as return-stack pointer. Note the 10 bytes at the start of foo that
    are not shown. If I disassemble that code (into AT&T syntax), it
    looks as follows:

    0x10226000: mov %rax,%rax
    0x10226003: sub $0x8,%rbp
    0x10226007: pop 0x0(%rbp)
    0x1022600a: pop %rbx
    0x1022600b: or %rbx,%rbx
    0x1022600e: je 0x10226016
    0x10226014: call *%rbx
    0x10226016: mov 0x0(%rbp),%rax
    0x1022601a: add $0x8,%rbp
    0x1022601e: jmp *%rax

    So here we see the first and last three instructions disassembled
    (which "idis" does not do). The third instruction moves the return
    address from the RSP stack to the RBP stack, and the second
    instruction adjusts RBP for that. Note that this invocation via call
    is not the usual way to invoke a colon definition from compiled code
    in iForth. E.g.:

    FORTH> : x . . ;
    FORTH> ' x idis
    $10226940 : x 488BC04883ED088F4500 H.@H.m..E. $1022694A lea rbp, [rbp -8 +] qword
    488D6DF8 H.mx $1022694E mov [rbp 0 +] qword, $1022695B d#
    48C745005B692210 HGE.[i". $10226956 jmp .+A ( $1013888A ) offset NEAR
    E92F1FF1FF i/.q. $1022695B jmp .+A ( $1013888A ) offset NEAR
    E92A1FF1FF i*.q. $10226960 ; 488B45004883C508FFE0 H.E.H.E..`

    Note that both calls to "." jump to ".+A", i.e., they skip the first
    three instructions. The first invocation of "." pushes the return
    address explicitly in the instructions at $1022694A and $1022694E, the
    second invocation is a tail-call.

    Back to EXECUTE: This means that iForth implements EXECUTE as pushing
    the return address (in a convoluted way).


    In the general case (no-tail EXECUTE) in all these native-code systems
    a compiled EXECUTE pushes the return address.

    This is not a problem for standard code because colon definitions and does>-following code is not allowed to inspect stuff on the return
    stack that it did not push there, and because other words either don't
    access the return stack, or ticking them is non-standard (e.g., ' R@
    is non-standard).

    Could it be done without call? How would the return to the code after
    the EXECUTE happen? One way to do it would be as follows:

    The code for general (non-tail) EXECUTE:

    ... stack adjustments
    mov rax, ra
    jmp rdx # execute the xt
    ra:

    and for a constant the xt code would be:

    ... stack adjustment
    mov rbx, const
    jmp rax

    while for a colon definition the xt code would be:

    push rax
    entry: #entry point for compiled code
    ... code of the colon definition
    ret

    The disadvantage of the scheme is that it does not pair the ret with a
    call, but with a push, which leads to slow branch mispredictions. It
    seems to me that if you want to use ret for EXIT and call for compiled
    colon definitions, having a call for a non-tail EXECUTE is the most
    efficient way to go.

    - anton
    --
    M. Anton Ertl http://www.complang.tuwien.ac.at/anton/home.html
    comp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html
    New standard: https://forth-standard.org/
    EuroForth 2023 proceedings: http://www.euroforth.org/ef23/papers/
    EuroForth 2024 proceedings: http://www.euroforth.org/ef24/papers/
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From dxf@dxforth@gmail.com to comp.lang.forth on Mon Mar 17 20:34:19 2025
    From Newsgroup: comp.lang.forth

    On 17/03/2025 5:12 pm, Anton Ertl wrote:
    dxf <dxforth@gmail.com> writes:
    Would you agree 'nest-sys' are peculiar to colon definitions. That
    EXECUTE is a different class of function. It's not doing a 'call'
    as such and not leaving anything on the 'return stack'?

    That's certainly the case for threaded-code implementations.

    For native-code implementations the implementation of EXECUTE is
    usually an indirect call; sometimes an indirect tail-call, i.e. a
    jump.
    ...

    Yes. Also for optimizing native-code it may be 'xt EXECUTE' itself will
    be optimized away. Since the Standard doesn't specify a nest-sys in
    relation to EXECUTE we can safely assume there isn't one? If not, when
    would it be an issue?

    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From albert@albert@spenarnc.xs4all.nl to comp.lang.forth on Mon Mar 17 12:47:48 2025
    From Newsgroup: comp.lang.forth

    In article <2025Mar17.071238@mips.complang.tuwien.ac.at>,
    Anton Ertl <anton@mips.complang.tuwien.ac.at> wrote:
    dxf <dxforth@gmail.com> writes:
    Would you agree 'nest-sys' are peculiar to colon definitions. That
    EXECUTE is a different class of function. It's not doing a 'call'
    as such and not leaving anything on the 'return stack'?

    That's certainly the case for threaded-code implementations.

    For native-code implementations the implementation of EXECUTE is
    usually an indirect call; sometimes an indirect tail-call, i.e. a
    jump.

    In VFX64 5.43:

    : foo execute ; ok
    see foo
    FOO
    ( 0050A250 488BD3 ) MOV RDX, RBX
    ( 0050A253 488B5D00 ) MOV RBX, [RBP]
    ( 0050A257 488D6D08 ) LEA RBP, [RBP+08]
    ( 0050A25B 48FFD2 ) CALL RDX
    ( 0050A25E C3 ) RET/NEXT

    However:

    see execute
    EXECUTE
    ( 004211B0 53 ) PUSH RBX
    ( 004211B1 488B5D00 ) MOV RBX, [RBP]
    ( 004211B5 488D6D08 ) LEA RBP, [RBP+08]
    ( 004211B9 C3 ) RET/NEXT
    ( 10 bytes, 4 instructions )

    The push-ret combination is an extremely slow form of an indirect
    jump; so where is the return address (nest-sys) here? It's the return >address of the surrounding call. E.g., if you do

    ' + ' execute foo

    it's the call in FOO.


    SwiftForth 4.0.0-RC89:

    see foo
    4519B7 4028CB ( EXECUTE ) JMP E90F0FFBFF ok

    That's a tail-call to EXECUTE. When EXECUTE is not tail-called, the
    code of EXECUTE is invoked with call:

    : bar execute . ; ok
    see bar
    4519D3 4028CB ( EXECUTE ) CALL E8F30EFBFF
    4519D8 40B043 ( . ) JMP E96696FBFF ok

    see execute
    4028CB RBX RCX MOV 488BCB
    4028CE 0 [RBP] RBX MOV 488B5D00
    4028D2 8 [RBP] RBP LEA 488D6D08
    4028D6 4028DD JRCXZ E305
    4028D8 RDI RCX ADD 4801F9
    4028DB RCX JMP FFE1
    4028DD RET C3 ok

    This special-cases the 0 EXECUTE case as NOOP, and also adds an offset
    (the image start?) to the xt before performing the indirect jump, but
    if you ignore those parts, this EXECUTE does the same things as VFX's,
    except that it uses the much faster indirect jmp rather than push-ret.


    lxf 1.7-172-983:
    see foo
    8692BC4 8050E6E 11 88C8000 5 normal FOO

    8050E6E 8BC3 mov eax , ebx
    8050E70 8B5D00 mov ebx , [ebp]
    8050E73 8D6D04 lea ebp , [ebp+4h]
    8050E76 FFD0 call eax
    8050E78 C3 ret near

    Here the EXECUTE is compiled inline and essentially implemented as
    indirect call. lxf does not perform tail-call optimization.

    see execute
    868E2FC 88D6B47 11 88D475B 92 prim EXECUTE

    88D6B47 8BC3 mov eax , ebx
    88D6B49 8B5D00 mov ebx , [ebp]
    88D6B4C 8D6D04 lea ebp , [ebp+4h]
    88D6B4F FFD0 call eax
    88D6B51 C3 ret near

    The same code as FOO; after all, both words do the same thing.


    iForth 5.1-mini (I think):

    FORTH> ' foo idis
    $10226000 : foo 488BC04883ED088F4500 H.@H.m..E. >$1022600A pop rbx 5B [
    $1022600B or rbx, rbx 4809DB H.[ >$1022600E je $10226016 offset NEAR
    0F8402000000 ......
    $10226014 call rbx FFD3 .S >$10226016 ; 488B45004883C508FFE0 H.E.H.E..` ok

    The use of call here is interesting, because iForth uses RSP as
    data-stack pointer (e.g., the "pop rbx" moves the xt into rbx) and rbp
    as return-stack pointer. Note the 10 bytes at the start of foo that
    are not shown. If I disassemble that code (into AT&T syntax), it
    looks as follows:

    0x10226000: mov %rax,%rax
    0x10226003: sub $0x8,%rbp
    0x10226007: pop 0x0(%rbp)
    0x1022600a: pop %rbx
    0x1022600b: or %rbx,%rbx
    0x1022600e: je 0x10226016
    0x10226014: call *%rbx
    0x10226016: mov 0x0(%rbp),%rax
    0x1022601a: add $0x8,%rbp
    0x1022601e: jmp *%rax

    So here we see the first and last three instructions disassembled
    (which "idis" does not do). The third instruction moves the return
    address from the RSP stack to the RBP stack, and the second
    instruction adjusts RBP for that. Note that this invocation via call
    is not the usual way to invoke a colon definition from compiled code
    in iForth. E.g.:

    FORTH> : x . . ;
    FORTH> ' x idis
    $10226940 : x 488BC04883ED088F4500 H.@H.m..E. >$1022694A lea rbp, [rbp -8 +] qword
    488D6DF8 H.mx
    $1022694E mov [rbp 0 +] qword, $1022695B d#
    48C745005B692210 HGE.[i".
    $10226956 jmp .+A ( $1013888A ) offset NEAR
    E92F1FF1FF i/.q.
    $1022695B jmp .+A ( $1013888A ) offset NEAR
    E92A1FF1FF i*.q.
    $10226960 ; 488B45004883C508FFE0 H.E.H.E..`

    Note that both calls to "." jump to ".+A", i.e., they skip the first
    three instructions. The first invocation of "." pushes the return
    address explicitly in the instructions at $1022694A and $1022694E, the
    second invocation is a tail-call.

    Back to EXECUTE: This means that iForth implements EXECUTE as pushing
    the return address (in a convoluted way).


    In the general case (no-tail EXECUTE) in all these native-code systems
    a compiled EXECUTE pushes the return address.

    This is not a problem for standard code because colon definitions and >does>-following code is not allowed to inspect stuff on the return
    stack that it did not push there, and because other words either don't
    access the return stack, or ticking them is non-standard (e.g., ' R@
    is non-standard).

    Could it be done without call? How would the return to the code after
    the EXECUTE happen? One way to do it would be as follows:

    The code for general (non-tail) EXECUTE:

    ... stack adjustments
    mov rax, ra
    jmp rdx # execute the xt
    ra:

    and for a constant the xt code would be:

    ... stack adjustment
    mov rbx, const
    jmp rax

    while for a colon definition the xt code would be:

    push rax
    entry: #entry point for compiled code
    ... code of the colon definition
    ret

    The disadvantage of the scheme is that it does not pair the ret with a
    call, but with a push, which leads to slow branch mispredictions. It
    seems to me that if you want to use ret for EXIT and call for compiled
    colon definitions, having a call for a non-tail EXECUTE is the most
    efficient way to go.

    To top it off. Indirect threaded code, with RSP the data stack:

    CODE EXECUTE
    POP WOR ; working register contains pointer to header
    JMP [WOR + CODE_OFFSET] ; Assuming the code field is at CODE_OFFSET.

    In ciforth I made this offset 0 for a slight gain in efficiency:
    1224 0df8 58 POP %RAX # GET HEADER
    1225 0df9 FF20 JMP QWORD PTR[%RAX] #(IP) <- (CFA)

    DOCOL in the code field does the nesting, but maybe it is a code word like DROP.


    - anton

    Groetjes Albert
    --
    Temu exploits Christians: (Disclaimer, only 10 apostles)
    Last Supper Acrylic Suncatcher - 15Cm Round Stained Glass- Style Wall
    Art For Home, Office And Garden Decor - Perfect For Windows, Bars,
    And Gifts For Friends Family And Colleagues.
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From albert@albert@spenarnc.xs4all.nl to comp.lang.forth on Mon Mar 17 12:54:53 2025
    From Newsgroup: comp.lang.forth

    In article <88dd79f886cd3b889c04f6fabb835587ce0cf724@i2pn2.org>,
    dxf <dxforth@gmail.com> wrote:
    On 17/03/2025 5:12 pm, Anton Ertl wrote:
    dxf <dxforth@gmail.com> writes:
    Would you agree 'nest-sys' are peculiar to colon definitions. That
    EXECUTE is a different class of function. It's not doing a 'call'
    as such and not leaving anything on the 'return stack'?

    That's certainly the case for threaded-code implementations.

    For native-code implementations the implementation of EXECUTE is
    usually an indirect call; sometimes an indirect tail-call, i.e. a
    jump.
    ...

    Yes. Also for optimizing native-code it may be 'xt EXECUTE' itself will
    be optimized away. Since the Standard doesn't specify a nest-sys in
    relation to EXECUTE we can safely assume there isn't one? If not, when
    would it be an issue?


    If xt is a dictionary level word, I can optimise
    ['] FORTHWORD EXECUTE
    by
    FORTHWORD
    This has nothing to do with threading, or native code.

    Groetjes Albert
    --
    Temu exploits Christians: (Disclaimer, only 10 apostles)
    Last Supper Acrylic Suncatcher - 15Cm Round Stained Glass- Style Wall
    Art For Home, Office And Garden Decor - Perfect For Windows, Bars,
    And Gifts For Friends Family And Colleagues.
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From Hans Bezemer@the.beez.speaks@gmail.com to comp.lang.forth on Mon Mar 17 13:12:55 2025
    From Newsgroup: comp.lang.forth

    On 17-03-2025 02:14, dxf wrote:
    Would you agree 'nest-sys' are peculiar to colon definitions. That
    EXECUTE is a different class of function. It's not doing a 'call'
    as such and not leaving anything on the 'return stack'?

    Ok, in order to answer that question, I'll always fall back to the standard:

    6.1.0070: "When interpreting, ' xyz EXECUTE is *equivalent* to xyz."

    Alright. In my book, that smells like a CALL. I was doubting for a
    second where Forth would land after executing EXECUTE. I'd say - after EXECUTE.

    How did it know it had to land there? Now I know there are some weird
    methods of achieving that (like patching the return address of the subroutine), but I'm not in the habit of seriously considering these.

    My code just says:

    CODE (EXECUTE) DSIZE (1); a = DPOP; RPUSH ((cell) PROGCOUNT);
    XT (a); JUMP (a); NEXT;

    It's not that different from:

    CODE (CALL) RFREE (1); RPUSH ((cell) PROGCOUNT);
    JUMP (OPERAND); NEXT;

    (And no, there is not an error there. 4tH has a shared stack, so if
    there is room on the data stack, and that item is removed, there is now
    space on the return stack.)

    In short - why is it not doing "a call"? Because it is not a jump.

    Hans Bezemer

    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From anton@anton@mips.complang.tuwien.ac.at (Anton Ertl) to comp.lang.forth on Mon Mar 17 17:46:56 2025
    From Newsgroup: comp.lang.forth

    dxf <dxforth@gmail.com> writes:
    Also for optimizing native-code it may be 'xt EXECUTE' itself will
    be optimized away.

    Yes:

    Gforth (development):
    : foo ['] . execute ; ok
    see foo
    : foo
    . ; ok

    That's a result of the constant-folding optimization. I wonder how
    often it triggers. Probably not much in real-world code.

    Since the Standard doesn't specify a nest-sys in
    relation to EXECUTE we can safely assume there isn't one?

    That's the question: The standard does not specify the nest-sys, so
    how can the native-code systems get away with implementing EXECUTE as
    call? It's because there is no standard way to observe the return
    address pushed by that call.

    The way the standard describes what happens corresponds to an
    indirect-threaded code system: EXECUTE does not push a return
    address/nest-sys, and for, e.g., constants, there is never a return
    address pushed. The initiation semantics of a colon definition (i.e.,
    docol) pushes the return address/nest-sys.

    Native-code systems deal with it a little differently, but that
    difference causes no standard-observable change in behaviour.

    - anton
    --
    M. Anton Ertl http://www.complang.tuwien.ac.at/anton/home.html
    comp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html
    New standard: https://forth-standard.org/
    EuroForth 2023 proceedings: http://www.euroforth.org/ef23/papers/
    EuroForth 2024 proceedings: http://www.euroforth.org/ef24/papers/
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From dxf@dxforth@gmail.com to comp.lang.forth on Tue Mar 18 17:48:15 2025
    From Newsgroup: comp.lang.forth

    On 17/03/2025 11:12 pm, Hans Bezemer wrote:
    On 17-03-2025 02:14, dxf wrote:
    Would you agree 'nest-sys' are peculiar to colon definitions.  That
    EXECUTE is a different class of function.  It's not doing a 'call'
    as such and not leaving anything on the 'return stack'?

    Ok, in order to answer that question, I'll always fall back to the standard:

    6.1.0070: "When interpreting, ' xyz EXECUTE is *equivalent* to xyz."

    Alright. In my book, that smells like a CALL. I was doubting for a second where Forth would land after executing EXECUTE. I'd say - after EXECUTE.

    How did it know it had to land there? Now I know there are some weird methods of achieving that (like patching the return address of the subroutine), but I'm not in the habit of seriously considering these.

    My code just says:

    CODE (EXECUTE)  DSIZE (1); a = DPOP; RPUSH ((cell) PROGCOUNT);                 XT (a); JUMP (a); NEXT;

    It's not that different from:

    CODE (CALL)     RFREE (1); RPUSH ((cell) PROGCOUNT);                 JUMP (OPERAND); NEXT;

    (And no, there is not an error there. 4tH has a shared stack, so if there is room on the data stack, and that item is removed, there is now space on the return stack.)

    In short - why is it not doing "a call"? Because it is not a jump.

    My bad. While EXECUTE might not push a 'nest-sys' onto the return stack,
    there seems to be no issue doing so. E.g. the following works under
    SwiftForth (native code, CALLed EXECUTE) irrespective of which definition
    of LOCAL was used.

    : ;: ( nest-sys -- ) >r ;

    \ : LOCAL ( x adr -- ) r> -rot dup @ over 2>r ! ;: 2r> ! ;
    : LOCAL ( x adr -- ) r> -rot dup @ over 2>r ! ['] ;: execute 2r> ! ;

    \ Example
    variable A variable B 8 a ! 7 b !

    : divide ( a b -- ) b local a local
    a @ b @ / . cr ;

    15 3 divide a ? b ?


    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From albert@albert@spenarnc.xs4all.nl to comp.lang.forth on Tue Mar 18 11:17:14 2025
    From Newsgroup: comp.lang.forth

    In article <2025Mar17.184656@mips.complang.tuwien.ac.at>,
    Anton Ertl <anton@mips.complang.tuwien.ac.at> wrote:
    dxf <dxforth@gmail.com> writes:
    Also for optimizing native-code it may be 'xt EXECUTE' itself will
    be optimized away.

    Yes:

    Gforth (development):
    : foo ['] . execute ; ok
    see foo
    : foo
    . ; ok

    That's a result of the constant-folding optimization. I wonder how
    often it triggers. Probably not much in real-world code.

    With good optimisers it can trigger often. You have revectored
    something. As least as the optimiser noticed the vector
    has been set and not changed this optimisation kicks in.
    This is a special case of:
    optimisation in Forth that notices that data fetched need not
    be fetched over again. This requires that analysis guarantees
    that the data cannot be changed. This is hard.

    - anton

    Groetjes Albert
    --
    Temu exploits Christians: (Disclaimer, only 10 apostles)
    Last Supper Acrylic Suncatcher - 15Cm Round Stained Glass- Style Wall
    Art For Home, Office And Garden Decor - Perfect For Windows, Bars,
    And Gifts For Friends Family And Colleagues.
    --- Synchronet 3.20c-Linux NewsLink 1.2